Running scHLA count
Prepare reference genotype files
# Assemble key linking sample-pool to simplified sample
hla_samples <- read_tsv("../../covid/isb/scHLAcount/all_fastq_files.txt", col_names = "file") %>%
filter(grepl("^INCOV", file)) %>%
filter(grepl("-BL", file)) %>%
separate(file, into = c("sample", NA), sep = "_", remove = F) %>%
drop_na()
# From all genotype field results, assemble highest resolution genotype for all sample:genotypers
select_last_allele <- function(x){
x[!is.na(x)] %>%
tail(1) %>%
str_replace_all("_", ":")}
hla_key <- all_hla_expanded %>%
rowwise() %>%
filter(grepl("^[ABC]", locus)) %>%
mutate(allele = select_last_allele(across(contains("field")))) %>%
select(sample, genotyper, locus, allele) %>%
unite(allele, locus, allele, sep = "*")
# Merge into key of list of genotypes for each sample-pool:genotyper pair
hla_merge <- hla_samples %>%
left_join(hla_key, by = "sample") %>%
drop_na() %>%
select(-sample) %>%
group_by(file, genotyper) %>%
nest()
# # Write keys to set of csvs for input to scHLAcount
# hla_merge %>%
# mutate(write = pmap(list(data, file, genotyper), function(d,f,g){
# dir <- sprintf("../../covid/isb/scHLAcount/genotypes/%s",g)
# if (!dir.exists(dir)){dir.create(dir, recursive = T)}
# write_tsv(d,
# sprintf("%s/%s_hla.tsv",dir,f),
# col_names = F,
# )}))
Run script
sbatch /covid/scripts/isb_scHLAcount_benchmark.sh
#!/bin/sh
#SBATCH --mail-type=END,FAIL
#SBATCH --mail-user=solomonb@stanford.edu
#SBATCH --time=13-23:05 # Runtime in D-HH:MM
#SBATCH --job-name=SCHLA
#SBATCH --nodes=1 # Ensure that all cores are reserved on one machine
#SBATCH --ntasks=6
#SBATCH --cpus-per-task=8
#SBATCH --mem-per-cpu=7G
#SBATCH --partition=khatrilab # Partition allocated for the lab
#SBATCH --error=./slurm_logs/%x.err
#SBATCH --output=./slurm_logs/%x.out
# SET GLOBAL VARIABLES
# General
export BASE_DIR=/labs/khatrilab/solomonb/covid/isb/scHLAcount
export LOG_DIR=$BASE_DIR/logs/$(date +'%y%m%d_%H%M%S')
# FASTQ/HISAT
export INDEX_DIR=/labs/khatrilab/solomonb/rnaseq_processing/hisat2/hisat_arcas/hisat_data/grch38
export BAM_DIR=$BASE_DIR/bam
# HLA references
export HLA_DIR=$BASE_DIR/hla_references
export HLANUC=/labs/khatrilab/solomonb/references/IMGTHLA/hla_nuc.fasta
export HLAGEN=/labs/khatrilab/solomonb/references/IMGTHLA/hla_gen.fasta
# SCHLA
export BARCODE_DIR=$BASE_DIR/barcodes
export GENOTYPE_DIR=$BASE_DIR/genotypes
export SCHLACOUNT_DIR=$BASE_DIR/output
export TEMP_DIR=$BASE_DIR/temp_fastq
# SLURM
export N_CORES=$SLURM_CPUS_PER_TASK
# CREATE DIRECTORIES
if [ ! -d $LOG_DIR ]; then mkdir -p $LOG_DIR;fi
if [ ! -d $BAM_DIR ]; then mkdir -p $BAM_DIR;fi
if [ ! -d $SCHLACOUNT_DIR ]; then mkdir -p $SCHLACOUNT_DIR;fi
if [ ! -d $TEMP_DIR ]; then mkdir -p $TEMP_DIR;fi
# CREATE HLA REFERECE ##########################################################
HLA_REFERENCE(){
source /labs/khatrilab/solomonb/miniconda3/etc/profile.d/conda.sh
conda activate samtools
printf "\n\
########################## CREATE REFERENCE ####################################\
\n" >> $LOG_DIR/${1}/${1}_${2}.log
printf "\n### [START___REFERENCE___$(date +'%D %X')]\n" >> $LOG_DIR/${1}/${1}_${2}.log
[ ! -d $HLA_DIR/${2} ] && mkdir -p $HLA_DIR/${2}
while read -r line; do grep -F -m 1 $line $HLANUC >> $HLA_DIR/${2}/${1}_tmpallele.txt; done < $GENOTYPE_DIR/${2}/${1}_hla.tsv
samtools faidx $HLANUC $(cut -f1 -d' ' $HLA_DIR/${2}/${1}_tmpallele.txt | tr '>' ' ' | tr '\n' ' ') > $HLA_DIR/${2}/${1}_cds.fasta 2>> $LOG_DIR/${1}/${1}_${2}.log
samtools faidx $HLAGEN $(cut -f1 -d' ' $HLA_DIR/${2}/${1}_tmpallele.txt | tr '>' ' ' | tr '\n' ' ') > $HLA_DIR/${2}/${1}_gen.fasta 2>> $LOG_DIR/${1}/${1}_${2}.log
while read -r line; do IFS=' '; read -r f1 f2 <<<"$line"; sed -i"" "s/$f1/$f1 $f2/g" $HLA_DIR/${2}/${1}_cds.fasta; done < $HLA_DIR/${2}/${1}_tmpallele.txt 2>> $LOG_DIR/${1}/${1}_${2}.log
while read -r line; do IFS=' '; read -r f1 f2 f3 <<<"$line"; sed -i"" "s/$f1/$f1 $f2/g" $HLA_DIR/${2}/${1}_gen.fasta; done < $HLA_DIR/${2}/${1}_tmpallele.txt 2>> $LOG_DIR/${1}/${1}_${2}.log
rm $HLA_DIR/${2}/${1}_tmpallele.txt
printf "### [COMPLETE___REFERENCE___$(date +'%D %X')]\n" >> $LOG_DIR/${1}/${1}_${2}.log
}
export -f HLA_REFERENCE
# DEFINE scHLA GENOTYPING PIPELINE #############################################
SCHLACOUNT(){
source /labs/khatrilab/solomonb/miniconda3/etc/profile.d/conda.sh
conda activate samtools
printf "\n\
########################## RUN SCHLACOUNT ####################################\
\n" >> $LOG_DIR/${1}/${1}_${2}.log
printf "\n### [START___SCHLACOUNT___$(date +'%D %X')]\n" >> $LOG_DIR/${1}/${1}_${2}.log
echo "### Starting scHLAcount at $(date +'%D %X')" >> $LOG_DIR/${1}/${1}_${2}.log
# if [ -d $SCHLACOUNT_DIR/${1}_results ]; then rm -r $SCHLACOUNT_DIR/${1}_results;fi
[ ! -d SCHLACOUNT_DIR/${2} ] && mkdir -p $SCHLACOUNT_DIR/${2}
sc_hla_count \
--bam $BAM_DIR/${1}.bam \
--cell-barcodes $BARCODE_DIR/${1}_barcode.tsv \
--out-dir $SCHLACOUNT_DIR/${2}/${1}_results \
--fasta-cds $HLA_DIR/${2}/${1}_cds.fasta \
--fasta-genomic $HLA_DIR/${2}/${1}_gen.fasta\
>> $LOG_DIR/${1}/${1}_${2}.log \
2>> $LOG_DIR/${1}/${1}_${2}.log
printf "### [COMPLETE___SCHLACOUNT___$(date +'%D %X')]\n" >> $LOG_DIR/${1}/${1}_${2}.log
}
export -f SCHLACOUNT
# DEFINE PIPELINE CONTROLLER FUNCTION ##########################################
PIPELINE(){
echo "START: sample $1 at $(date +'%D %X')"
for G in arcasHLA hlaminer invitro optitype phlat
do
[ ! -d $LOG_DIR/${1} ] && mkdir -p $LOG_DIR/${1}
HLA_REFERENCE $1 $G
SCHLACOUNT $1 $G
done
echo "COMPLETE: sample $1 at $(date +'%D %X')"
}
export -f PIPELINE
cat $BASE_DIR/BL_fastq_files.txt | parallel --delay 15 -j $SLURM_NTASKS --joblog $LOG_DIR/parallel.log PIPELINE {}
UMAP projections
Cell clusters
srt <- readRDS("/labs/khatrilab/hongzheng/webapps/isb/srt_isb260.meta.rds")
cells <- c("CD14 Monocyte", "CD4 T", "CD8 T", "NK", "B", "CD16 Monocyte", "cDC", "pDC")
# srt <- srt %>% filter(celltype %in% cells)
# ggplot theme to overlay cluster id #s on UMAP
gg_srt_relabel <- function(df, x_var, y_var, color_var, cell_fraction = 1){
plt <- df %>%
ggplot(aes(x = !!sym(x_var), y = !!sym(y_var), color = !!sym(color_var))) +
geom_point(size = 0.5, alpha = 0.5)+
theme_bw() +
scale_color_brewer(palette = "Dark2")+
guides(color = guide_legend(override.aes = list(size = 2, alpha = 1)))
g <- ggplot_build(plt)
plt_ids <- g$data[[1]]
group_levels <- levels(factor(g$plot$data[[g$plot$labels$colour]]))
plt_key <- g$data[[1]] %>%
select(colour, group) %>%
distinct() %>%
mutate(label = map_chr(group, function(x) group_levels[x])) %>%
mutate(label = factor(label, level = group_levels)) %>%
mutate(label = sprintf("%s) %s", 1:n(), label)) %>%
select(-group)
plt_df <- plt_ids %>%
left_join(plt_key, by = "colour")
plt_center <- plt_df %>%
group_by(label) %>% summarise(x = mean(x), y = mean(y)) %>%
mutate(label = gsub(").*","",label))
plt_repel <- plt_df %>%
ggplot(aes(x=x,y=y,color=label)) +
geom_point(size = 0.5)+
ggrepel::geom_text_repel(data=plt_center,
aes(label=label, bg.color="white", bg.r=0.25),
color = "black",
fontface = "bold") +
theme_bw() +
guides(color = guide_legend(override.aes = list(size = 2) ) ) +
labs(x=x_var, y = y_var, color = color_var) +
theme(axis.text = element_blank(), axis.ticks = element_blank())
return(plt_repel)
}
plt_srt <- srt %>%
filter(celltype %in% cells) %>%
filter(sampleID == "INCOV069-BL") %>%
gg_srt_relabel(x_var = "UMAP_1", y_var = "UMAP_2", color_var = "celltype", cell_fraction = 0.1) +
scale_color_brewer(palette = "Dark2")+
theme(axis.text = element_blank(), axis.ticks = element_blank()) +
labs(x="UMAP 1", y = "UMAP 2", color = "Cell Cluster")
plt_srt

Allele frequency
samp <- "INCOV069-BL"
# samp <- "INCOV028-BL"
gene_select <- "A"
scHLAcount_dir <- sprintf("%s/scHLAcount", isb_path)
# Create tibble of all genotyper and sample combinations
allele_data <- expand_grid(
genotyper = c("invitro", "arcasHLA", "optitype", "phlat", "hlaminer"),
sample = read_lines(
"/labs/khatrilab/solomonb/covid/isb/scHLAcount/BL_fastq_files.txt"
)) %>%
filter(grepl(samp, sample)) %>%
# Import data based on sample and genotyper
mutate(result_path = sprintf("%s/output/%s",scHLAcount_dir, genotyper),
barcode_path = sprintf("%s/barcodes", scHLAcount_dir)) %>%
mutate(data = pmap(list(sample, result_path, barcode_path), function(s,r,b){
df <- scHLA_data_processing(
sample=s,
result_dir=r,
barcode_dir=b
)
})) %>% unnest(data)
allele_data_ratios <- allele_data %>%
filter(gene == gene_select) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
mutate(allele_order = fct_recode(factor(allele_order), "Allele 1" = "1", "Allele 2" = "2"))
allele_data
allele_label <- allele_data_ratios %>%
select(genotyper, allele_order, allele) %>%
distinct()
plt <- srt %>%
left_join(allele_data_ratios %>% filter(gene == gene_select), by = "cell") %>%
filter(!is.na(allele)) %>%
ggplot(aes(x = UMAP_1, y = UMAP_2, color = allele_ratio)) +
geom_point(size = 0.5, alpha = 0.5)+
theme_bw() +
facet_grid(allele_order~genotyper)+
scale_color_gradient2(high = "red", mid = "grey80", low = "blue", midpoint = 0.5, na.value = "transparent") +
labs(x="UMAP 1", y="UMAP 2", color = "Allele \nFrequency")+
theme(axis.ticks = element_blank(), axis.text = element_blank())+
coord_cartesian(ylim = c(-10,15))
plt_allele_freq <- plt+
geom_label(data = allele_label, aes(x=-10,y=14, color = NULL, label = allele), size = 3, hjust = 0)
plt_allele_freq

Maximum allele

plt_max_allele$genotyper %>% reformat_hla_genotyper() %>% levels()
[1] "Ground truth" "arcasHLA" "HLAminer" "PHLAT" "OptiType"
Meta-analysis approach
Rationale
- Goal: determine a summary statistic for allele ratio across all cells
- Problem:
- Each cell in scRNA experiment has its own ratio of HLA allele 1 reads : HLA allele 2 reads
- A wide range of total read counts may go into each cell’s ratio
- Small difference in read counts for cells with low total reads can greatly alter the allele ratio compared to cells with high total read counts
- I.e. Cells with low read counts are more likely to have imprecise allele ratios
- Simply averaging ratios would equally weight high confidence, high read count ratios with low confidence, low read ratios
- Approach
- Meta-analysis methods specifically address type of problem, typically by weighing an effect by the inverse of its variance
- In the setting of ratios, basic approach would be to combine log-odds ratio of alleles, weighted by inverse variance
- Would use a random effects model because do not expect each cell in a group would have the same exact ratio due to various stochastic transcriptional effects
Calculating summary effect sizes
- Analysis can take some time, so run in slurm
- Contained in a separate script
./slurm/sc_meta.R:
Contents of sc_meta.R
library(tidyverse)
library(meta)
project_dir <- "/labs/khatrilab/solomonb/hla_project/hla_benchmark"
source(sprintf("%s/data_import_functions.R", project_dir))
isb_path <- "/labs/khatrilab/solomonb/covid/isb"
scHLAcount_dir <- sprintf("%s/scHLAcount", isb_path)
srt <- readRDS("/labs/khatrilab/hongzheng/webapps/isb/srt_isb260.meta.rds")
cells <- c("CD14 Monocyte", "CD4 T", "CD8 T", "NK", "B", "CD16 Monocyte", "cDC", "pDC")
# Function to perform meta-analysis on dataframe where
# each row is a cell and columns:
# `observed` (reads of dominant allele)
# `gene_sum_typed` (total cell reads)
# `expected` (reads of one allele expected if 50:50 allele_1 : allele_2)
sc_meta <- function(df){
l <- nrow(df)
m <- metabin(event.e = observed, n.e = gene_sum_typed, event.c = expected, n.c = gene_sum_typed,
data = df,
method = "Inverse",
incr = 0.1,
sm = "OR")
data.frame(summary(m)$random) %>%
mutate(n_cells = l) %>%
select(TE, seTE, lower, upper, n_cells)
}
# Import data based on sample and genotyper
cell_stats <- expand_grid(
genotyper = c("invitro", "arcasHLA", "optitype", "phlat", "hlaminer"),
sample = read_lines(
"/labs/khatrilab/solomonb/covid/isb/scHLAcount/BL_fastq_files.txt"
)) %>%
# head(5) %>% # Specify limit to number of meta-analyses
mutate(data = map2(sample, genotyper, function(s,g){
result_path = sprintf("%s/output/%s", scHLAcount_dir, g)
barcode_path = sprintf("%s/barcodes", scHLAcount_dir)
scHLA_data_processing(sample = s,
result_dir = result_path,
barcode_dir = barcode_path)
})) %>% unnest(data) %>%
filter(!is.na(cell)) %>%
mutate(sample = gsub("_[A-Z][0-9]$","",sample)) %>% # Consolidate samples
left_join(srt %>% select(celltype, cell), by = "cell") %>% # Add celltypes
filter(celltype %in% cells) # Keep only standard cell types
meta_df <- cell_stats %>%
# Keep only most expressed allele (or random if 50:50)
group_by(sample, genotyper, gene, cell) %>%
slice_max(order_by = allele_ratio, n = 1, with_ties = F) %>%
ungroup() %>%
# Fill out contingency table
mutate(complement = gene_sum_typed - count,
expected = 0.5*gene_sum_typed) %>%
rename(observed = count) %>%
select(sample, genotyper, celltype, gene, observed, expected, gene_sum_typed) %>%
group_by(sample, genotyper, celltype, gene) %>%
# Nest and run meta-analysis
nest() %>%
ungroup() %>%
mutate(data = map(data,function(x) {sc_meta(x)})) %>%
unnest(data)
write_csv(meta_df, sprintf("%s/slurm/meta_analysis_results.csv", project_dir))
Single sample analysis
meta_df <- read_csv("./slurm/meta_analysis_results.csv")
Rows: 7299 Columns: 9
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): sample, genotyper, celltype, gene
dbl (5): TE, seTE, lower, upper, n_cells
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
meta_df
# Single celltype and gene
samp <- "INCOV069-BL"
# samp <- "INCOV022-BL"
plt_meta <- meta_df %>%
filter(sample == samp) %>%
filter(celltype == "NK", gene == "A") %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
ggplot(aes(x = genotyper, y = TE, ymin = lower, ymax = upper))+
geom_point()+
geom_errorbar()+
theme_bw()+
scale_y_continuous(limits = c(0,NA))+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL)
plt_meta

samp <- "INCOV069-BL"
samples <- unique(meta_df$sample)
for (i in 1:length(samples)){
plt_meta <- meta_df %>%
filter(sample == samples[i]) %>%
filter(celltype == "CD14 Monocyte", gene == "A") %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
ggplot(aes(x = genotyper, y = TE, ymin = lower, ymax = upper))+
geom_point()+
geom_errorbar()+
theme_bw()+
scale_y_continuous(limits = c(0,NA))+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL) +
ggtitle(samples[i])
print(plt_meta)
}
































































# All celltypes and genes
meta_df %>%
mutate(
celltype = factor(celltype, levels = c(
"cDC", "CD14 Monocyte", "B", "pDC", "CD16 Monocyte", "CD8 T", "CD4 T", "NK"))) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
mutate(gene = reformat_hla_loci(gene)) %>%
ggplot(aes(x = celltype, y = TE, ymin = lower, ymax = upper, fill = celltype))+
geom_bar(stat = "identity", position = "dodge", color = "black", size = 0.25)+
geom_errorbar(position = position_dodge(0.9), width =0.5)+
theme_bw()+
facet_grid(gene~genotyper, scales = "free_y")+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

meta_df %>%
mutate(
celltype = factor(celltype, levels = c(
"cDC", "CD14 Monocyte", "B", "pDC", "CD16 Monocyte", "CD8 T", "CD4 T", "NK"))) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
mutate(gene = reformat_hla_loci(gene)) %>%
ggplot(aes(x = genotyper, y = TE, ymin = lower, ymax = upper, fill = celltype))+
geom_bar(stat = "identity", position = "dodge", color = "black", size = 0.25)+
geom_errorbar(position = position_dodge(0.9), width =0.5)+
theme_bw()+
facet_grid(gene~celltype, scales = "free_y")+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

Multi-sample analysis
meta_df <- read_csv("./slurm/meta_analysis_results.csv") %>%
mutate(genotyper = reformat_hla_genotyper(genotyper),
celltype = factor(celltype, levels = c(
"cDC", "CD14 Monocyte", "B", "pDC", "CD16 Monocyte", "CD8 T", "CD4 T", "NK")))
Rows: 7299 Columns: 9
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): sample, genotyper, celltype, gene
dbl (5): TE, seTE, lower, upper, n_cells
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
meta_df %>%
ggplot(aes(x=celltype,y=TE, fill = celltype))+
geom_violin()+
geom_jitter(alpha = 0.2, size = 0.2)+
stat_summary(fun=mean, stat= "point")+
stat_summary(fun.data = mean_se, geom="errorbar")+
facet_grid(gene~genotyper)+
theme_bw()+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

meta_df %>%
ggplot(aes(x=genotyper,y=TE, fill = celltype))+
geom_violin()+
geom_jitter(alpha = 0.2, size = 0.2)+
stat_summary(fun=mean, stat= "point")+
stat_summary(fun.data = mean_se, geom="errorbar")+
facet_grid(gene~celltype)+
theme_bw()+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

Correlation analysis
meta_df %>%
filter(gene == "A", celltype == "cDC") %>%
select(sample, genotyper, TE) %>%
pivot_wider(names_from = "genotyper", values_from = "TE") %>%
select(-sample) %>%
GGally::ggpairs(progress = FALSE) +
theme_bw()

accuracy_df <- readRDS("isb_accuracy_drb345_filtered.RDS") %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
select(sample, gene=locus, genotyper, accuracy) %>%
distinct()
for (i in c(0,1)){
suppressWarnings({
plt <- meta_df %>%
ungroup() %>%
filter(gene == "A", celltype == "cDC") %>%
left_join(accuracy_df, by = c("sample", "gene", "genotyper")) %>%
filter(accuracy == i | genotyper == "Ground truth") %>%
# drop_na(accuracy) %>%
select(sample, genotyper, TE) %>%
pivot_wider(names_from = "genotyper", values_from = "TE") %>%
select(-sample) %>%
GGally::ggpairs(progress = FALSE) +
theme_bw() +
ggtitle(sprintf("Correlation of allele ratios where accuracy = %s", i))
print(plt)
})
}


corr_df <- meta_df %>%
select(sample, genotyper, celltype, gene, TE) %>%
pivot_wider(names_from = "genotyper", values_from = "TE") %>%
pivot_longer(c(arcasHLA, HLAminer, OptiType, PHLAT), names_to = "genotyper", values_to = "TE") %>%
mutate(genotyper = reformat_hla_genotyper(genotyper))
corr_df %>%
ggplot(aes(x=`Ground truth`, y=TE))+
geom_point(size = 0.5)+
facet_grid(gene ~ genotyper) +
theme_bw() +
ggpubr::stat_cor(aes(label = ..rr.label..), label.x.npc = "left", label.y.npc = "top", geom = "label")

for (i in c(0,1)){
suppressWarnings({
plt <- corr_df %>%
ungroup() %>%
# filter(gene == "A", celltype == "cDC") %>%
left_join(accuracy_df, by = c("sample", "gene", "genotyper")) %>%
filter(accuracy == i) %>%
ggplot(aes(x=`Ground truth`, y=TE))+
geom_point(size = 0.5)+
facet_grid(gene ~ genotyper) +
theme_bw() +
ggpubr::stat_cor(aes(label = ..rr.label..), label.x.npc = "left", label.y.npc = "top", geom = "label") +
ggtitle(sprintf("Correlation of allele ratios where accuracy = %s", i)) +
labs(y = "Predicted genotype HLA allele log-odds ratio", x = "Ground truth genotype HLA allele log-odds ratio")
assign(sprintf("plt_meta_corr_%s", i), plt)
print(plt)
})
}
plt_meta_corr_abbrev <- corr_df %>%
left_join(accuracy_df, by = c("sample", "gene", "genotyper")) %>%
filter(gene == "A", accuracy %in% c(0,1)) %>%
ggplot(aes(x=`Ground truth`, y=TE))+
geom_point(size = 0.5)+
facet_grid(accuracy ~ genotyper, labeller = labeller(accuracy = function(x) sprintf("Accuracy: %s", x))) +
theme_bw() +
ggpubr::stat_cor(aes(label = ..rr.label..), label.x.npc = "left", label.y.npc = "top", geom = "label") +
labs(y = "Log-odds ratio using predicted genotype", x = "Log-odds ratio using ground truth genotyper")
plt_meta_corr_abbrev
By severity
meta_df %>%
filter(genotyper == "Ground truth") %>%
left_join(
srt %>%
select(sample = sampleID, severity) %>%
distinct(),
by = "sample"
) %>%
ggplot(aes(x=severity,y=TE, fill = celltype))+
geom_violin()+
geom_jitter(alpha = 0.2, size = 0.2)+
stat_summary(fun=mean, stat= "point")+
stat_summary(fun.data = mean_se, geom="errorbar")+
facet_grid(gene~celltype)+
theme_bw()+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

meta_df %>%
filter(genotyper == "Ground truth") %>%
left_join(
srt %>%
select(sample = sampleID, severity) %>%
distinct(),
by = "sample"
) %>%
mutate(severity = as.numeric(severity)) %>%
ggplot(aes(x = severity, y = TE)) +
geom_point() +
stat_smooth(method = "lm")+
facet_wrap(~celltype)+
theme_bw()
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 24 rows containing non-finite values (stat_smooth).
Warning: Removed 24 rows containing missing values (geom_point).

Assemble plot
# plt_allele_freq_lgd <- cowplot::get_legend(plt_allele_freq)
# plt_max_allele_lgd <- cowplot::get_legend(plt_max_allele)
col_1 <- plot_grid(
plt_allele_freq,
plt_max_allele,
ncol = 1,
rel_heights = c(5,3),
align = "v", axis = "lr",
labels = LETTERS[1:2]
)
col_2 <- plot_grid(
plt_srt,
plt_meta,
ncol = 1,
align = "v", axis = "lr",
labels = LETTERS[3:4],
hjust = 0.5
)
row_1 <- plot_grid(
col_1,
col_2,
nrow = 1,
rel_widths = c(6,3)
)
row_2 <- plot_grid(
plt_meta_corr_0 +ggtitle(NULL),
plt_meta_corr_1 +ggtitle(NULL),
labels = LETTERS[5:6],
ncol = 2
)
Warning: Removed 334 rows containing non-finite values (stat_cor).
Warning: Removed 334 rows containing missing values (geom_point).
Warning: Removed 14 rows containing non-finite values (stat_cor).
Warning: Removed 14 rows containing missing values (geom_point).
plot_grid(
row_1,
row_2,
rel_heights = c(3,2),
ncol = 1
)

col_1 <- plot_grid(
plt_srt,
plt_meta,
ncol = 1,
align = "v", axis = "lr",
labels = LETTERS[c(1,3)],
label_x = -0.05
)
col_2 <- plot_grid(
plt_max_allele,
plt_meta_corr_abbrev,
ncol = 1,
rel_heights = c(3,5),
align = "v", axis = "lr",
labels = LETTERS[c(2,4)],
label_x = -0.05
)
Warning: Removed 141 rows containing non-finite values (stat_cor).
Warning: Removed 141 rows containing missing values (geom_point).
plot_grid(
NULL,
col_1,
col_2,
nrow = 1,
rel_widths = c(0.25,3,6)
)

NA
NA
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKIyBTZXR1cApgYGB7ciwgbWVzc2FnZSA9IEZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1ldGEpCmxpYnJhcnkoY293cGxvdCkKc291cmNlKCJkYXRhX2ltcG9ydF9mdW5jdGlvbnMuUiIpCnNvdXJjZSgiZmlndXJlX2Zvcm1hdF9mdW5jdGlvbnMuUiIpCmFsbF9obGFfZXhwYW5kZWQgPC0gcmVhZFJEUygiYWxsX2hsYV9leHBhbmRlZC5SRFMiKQppc2JfcGF0aCA8LSAiL2xhYnMva2hhdHJpbGFiL3NvbG9tb25iL2NvdmlkL2lzYiIKYGBgCgoKIyBSdW5uaW5nIHNjSExBIGNvdW50CgojIyMgUHJlcGFyZSByZWZlcmVuY2UgZ2Vub3R5cGUgZmlsZXMKCmBgYHtyLCBldmFsPUZ9CiMgQXNzZW1ibGUga2V5IGxpbmtpbmcgc2FtcGxlLXBvb2wgdG8gc2ltcGxpZmllZCBzYW1wbGUKaGxhX3NhbXBsZXMgPC0gcmVhZF90c3YoIi4uLy4uL2NvdmlkL2lzYi9zY0hMQWNvdW50L2FsbF9mYXN0cV9maWxlcy50eHQiLCBjb2xfbmFtZXMgPSAiZmlsZSIpICU+JSAKICBmaWx0ZXIoZ3JlcGwoIl5JTkNPViIsIGZpbGUpKSAlPiUgCiAgZmlsdGVyKGdyZXBsKCItQkwiLCBmaWxlKSkgJT4lIAogIHNlcGFyYXRlKGZpbGUsIGludG8gPSBjKCJzYW1wbGUiLCBOQSksIHNlcCA9ICJfIiwgcmVtb3ZlID0gRikgJT4lIAogIGRyb3BfbmEoKQoKIyBGcm9tIGFsbCBnZW5vdHlwZSBmaWVsZCByZXN1bHRzLCBhc3NlbWJsZSBoaWdoZXN0IHJlc29sdXRpb24gZ2Vub3R5cGUgZm9yIGFsbCBzYW1wbGU6Z2Vub3R5cGVycwpzZWxlY3RfbGFzdF9hbGxlbGUgPC0gZnVuY3Rpb24oeCl7CiAgeFshaXMubmEoeCldICU+JQogICAgdGFpbCgxKSAlPiUgCiAgICBzdHJfcmVwbGFjZV9hbGwoIl8iLCAiOiIpfQpobGFfa2V5IDwtIGFsbF9obGFfZXhwYW5kZWQgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgZmlsdGVyKGdyZXBsKCJeW0FCQ10iLCBsb2N1cykpICU+JSAKICBtdXRhdGUoYWxsZWxlID0gc2VsZWN0X2xhc3RfYWxsZWxlKGFjcm9zcyhjb250YWlucygiZmllbGQiKSkpKSAlPiUgCiAgc2VsZWN0KHNhbXBsZSwgZ2Vub3R5cGVyLCBsb2N1cywgYWxsZWxlKSAlPiUgCiAgdW5pdGUoYWxsZWxlLCBsb2N1cywgYWxsZWxlLCBzZXAgPSAiKiIpCgojIE1lcmdlIGludG8ga2V5IG9mIGxpc3Qgb2YgZ2Vub3R5cGVzIGZvciBlYWNoIHNhbXBsZS1wb29sOmdlbm90eXBlciBwYWlyCmhsYV9tZXJnZSA8LSBobGFfc2FtcGxlcyAlPiUgCiAgbGVmdF9qb2luKGhsYV9rZXksIGJ5ID0gInNhbXBsZSIpICU+JSAKICBkcm9wX25hKCkgJT4lIAogIHNlbGVjdCgtc2FtcGxlKSAlPiUgCiAgZ3JvdXBfYnkoZmlsZSwgZ2Vub3R5cGVyKSAlPiUgCiAgbmVzdCgpCgojICMgV3JpdGUga2V5cyB0byBzZXQgb2YgY3N2cyBmb3IgaW5wdXQgdG8gc2NITEFjb3VudAojIGhsYV9tZXJnZSAlPiUgCiMgICBtdXRhdGUod3JpdGUgPSBwbWFwKGxpc3QoZGF0YSwgZmlsZSwgZ2Vub3R5cGVyKSwgZnVuY3Rpb24oZCxmLGcpewojICAgICBkaXIgPC0gc3ByaW50ZigiLi4vLi4vY292aWQvaXNiL3NjSExBY291bnQvZ2Vub3R5cGVzLyVzIixnKQojICAgICBpZiAoIWRpci5leGlzdHMoZGlyKSl7ZGlyLmNyZWF0ZShkaXIsIHJlY3Vyc2l2ZSA9IFQpfQojICAgICB3cml0ZV90c3YoZCwgCiMgICAgICAgICAgICAgICBzcHJpbnRmKCIlcy8lc19obGEudHN2IixkaXIsZiksIAojICAgICAgICAgICAgICAgY29sX25hbWVzID0gRiwKIyAgICAgICAgICAgICAgICl9KSkKYGBgCgoKIyMjIFJ1biBzY3JpcHQKCmBzYmF0Y2ggL2NvdmlkL3NjcmlwdHMvaXNiX3NjSExBY291bnRfYmVuY2htYXJrLnNoYAoKYGBge2Jhc2gsIGV2YWw9Rn0KIyEvYmluL3NoCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ELEZBSUwKI1NCQVRDSCAtLW1haWwtdXNlcj1zb2xvbW9uYkBzdGFuZm9yZC5lZHUKI1NCQVRDSCAtLXRpbWU9MTMtMjM6MDUgIyBSdW50aW1lIGluIEQtSEg6TU0KI1NCQVRDSCAtLWpvYi1uYW1lPVNDSExBCiNTQkFUQ0ggLS1ub2Rlcz0xICMgRW5zdXJlIHRoYXQgYWxsIGNvcmVzIGFyZSByZXNlcnZlZCBvbiBvbmUgbWFjaGluZQojU0JBVENIIC0tbnRhc2tzPTYKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9OAojU0JBVENIIC0tbWVtLXBlci1jcHU9N0cKI1NCQVRDSCAtLXBhcnRpdGlvbj1raGF0cmlsYWIgIyBQYXJ0aXRpb24gYWxsb2NhdGVkIGZvciB0aGUgbGFiCiNTQkFUQ0ggLS1lcnJvcj0uL3NsdXJtX2xvZ3MvJXguZXJyCiNTQkFUQ0ggLS1vdXRwdXQ9Li9zbHVybV9sb2dzLyV4Lm91dAoKIyBTRVQgR0xPQkFMIFZBUklBQkxFUwojIEdlbmVyYWwKZXhwb3J0IEJBU0VfRElSPS9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9jb3ZpZC9pc2Ivc2NITEFjb3VudApleHBvcnQgTE9HX0RJUj0kQkFTRV9ESVIvbG9ncy8kKGRhdGUgKycleSVtJWRfJUglTSVTJykKIyBGQVNUUS9ISVNBVApleHBvcnQgSU5ERVhfRElSPS9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9ybmFzZXFfcHJvY2Vzc2luZy9oaXNhdDIvaGlzYXRfYXJjYXMvaGlzYXRfZGF0YS9ncmNoMzgKZXhwb3J0IEJBTV9ESVI9JEJBU0VfRElSL2JhbQojIEhMQSByZWZlcmVuY2VzCmV4cG9ydCBITEFfRElSPSRCQVNFX0RJUi9obGFfcmVmZXJlbmNlcwpleHBvcnQgSExBTlVDPS9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9yZWZlcmVuY2VzL0lNR1RITEEvaGxhX251Yy5mYXN0YQpleHBvcnQgSExBR0VOPS9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9yZWZlcmVuY2VzL0lNR1RITEEvaGxhX2dlbi5mYXN0YQojIFNDSExBCmV4cG9ydCBCQVJDT0RFX0RJUj0kQkFTRV9ESVIvYmFyY29kZXMKZXhwb3J0IEdFTk9UWVBFX0RJUj0kQkFTRV9ESVIvZ2Vub3R5cGVzCmV4cG9ydCBTQ0hMQUNPVU5UX0RJUj0kQkFTRV9ESVIvb3V0cHV0CmV4cG9ydCBURU1QX0RJUj0kQkFTRV9ESVIvdGVtcF9mYXN0cQojIFNMVVJNIApleHBvcnQgTl9DT1JFUz0kU0xVUk1fQ1BVU19QRVJfVEFTSwoKCiMgQ1JFQVRFIERJUkVDVE9SSUVTCmlmIFsgISAtZCAkTE9HX0RJUiBdOyB0aGVuIG1rZGlyIC1wICRMT0dfRElSO2ZpCmlmIFsgISAtZCAkQkFNX0RJUiBdOyB0aGVuIG1rZGlyIC1wICRCQU1fRElSO2ZpCmlmIFsgISAtZCAkU0NITEFDT1VOVF9ESVIgXTsgdGhlbiBta2RpciAtcCAkU0NITEFDT1VOVF9ESVI7ZmkKaWYgWyAhIC1kICRURU1QX0RJUiBdOyB0aGVuIG1rZGlyIC1wICRURU1QX0RJUjtmaQoKIyBDUkVBVEUgSExBIFJFRkVSRUNFICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKSExBX1JFRkVSRU5DRSgpewogIHNvdXJjZSAvbGFicy9raGF0cmlsYWIvc29sb21vbmIvbWluaWNvbmRhMy9ldGMvcHJvZmlsZS5kL2NvbmRhLnNoCiAgY29uZGEgYWN0aXZhdGUgc2FtdG9vbHMKICAKICBwcmludGYgIlxuXAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBDUkVBVEUgUkVGRVJFTkNFICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI1wKICBcbiIgPj4gJExPR19ESVIvJHsxfS8kezF9XyR7Mn0ubG9nCiAgcHJpbnRmICJcbiMjIyBbU1RBUlRfX19SRUZFUkVOQ0VfX18kKGRhdGUgKyclRCAlWCcpXVxuIiA+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICAKICBbICEgLWQgJEhMQV9ESVIvJHsyfSBdICYmIG1rZGlyIC1wICRITEFfRElSLyR7Mn0KICAKICB3aGlsZSByZWFkIC1yIGxpbmU7IGRvIGdyZXAgLUYgLW0gMSAkbGluZSAkSExBTlVDID4+ICRITEFfRElSLyR7Mn0vJHsxfV90bXBhbGxlbGUudHh0OyBkb25lIDwgJEdFTk9UWVBFX0RJUi8kezJ9LyR7MX1faGxhLnRzdgogIAogIHNhbXRvb2xzIGZhaWR4ICAkSExBTlVDICQoY3V0IC1mMSAtZCcgJyAkSExBX0RJUi8kezJ9LyR7MX1fdG1wYWxsZWxlLnR4dCB8IHRyICc+JyAnICcgfCB0ciAnXG4nICcgJykgPiAkSExBX0RJUi8kezJ9LyR7MX1fY2RzLmZhc3RhIDI+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICBzYW10b29scyBmYWlkeCAgJEhMQUdFTiAkKGN1dCAtZjEgLWQnICcgJEhMQV9ESVIvJHsyfS8kezF9X3RtcGFsbGVsZS50eHQgfCB0ciAnPicgJyAnIHwgdHIgJ1xuJyAnICcpID4gJEhMQV9ESVIvJHsyfS8kezF9X2dlbi5mYXN0YSAyPj4gJExPR19ESVIvJHsxfS8kezF9XyR7Mn0ubG9nCiAgCiAgd2hpbGUgcmVhZCAtciBsaW5lOyBkbyBJRlM9JyAnOyByZWFkIC1yIGYxIGYyIDw8PCIkbGluZSI7IHNlZCAtaSIiICJzLyRmMS8kZjEgJGYyL2ciICRITEFfRElSLyR7Mn0vJHsxfV9jZHMuZmFzdGE7IGRvbmUgPCAkSExBX0RJUi8kezJ9LyR7MX1fdG1wYWxsZWxlLnR4dCAyPj4gJExPR19ESVIvJHsxfS8kezF9XyR7Mn0ubG9nCiAgd2hpbGUgcmVhZCAtciBsaW5lOyBkbyBJRlM9JyAnOyByZWFkIC1yIGYxIGYyIGYzIDw8PCIkbGluZSI7IHNlZCAtaSIiICJzLyRmMS8kZjEgJGYyL2ciICRITEFfRElSLyR7Mn0vJHsxfV9nZW4uZmFzdGE7IGRvbmUgPCAkSExBX0RJUi8kezJ9LyR7MX1fdG1wYWxsZWxlLnR4dCAyPj4gJExPR19ESVIvJHsxfS8kezF9XyR7Mn0ubG9nCiAgCiAgcm0gJEhMQV9ESVIvJHsyfS8kezF9X3RtcGFsbGVsZS50eHQKICBwcmludGYgIiMjIyBbQ09NUExFVEVfX19SRUZFUkVOQ0VfX18kKGRhdGUgKyclRCAlWCcpXVxuIiA+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKfQpleHBvcnQgLWYgSExBX1JFRkVSRU5DRQoKCiMgREVGSU5FIHNjSExBIEdFTk9UWVBJTkcgUElQRUxJTkUgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjClNDSExBQ09VTlQoKXsKICBzb3VyY2UgL2xhYnMva2hhdHJpbGFiL3NvbG9tb25iL21pbmljb25kYTMvZXRjL3Byb2ZpbGUuZC9jb25kYS5zaAogIGNvbmRhIGFjdGl2YXRlIHNhbXRvb2xzCiAgCiAgcHJpbnRmICJcblwKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgUlVOIFNDSExBQ09VTlQgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjXAogIFxuIiA+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICBwcmludGYgIlxuIyMjIFtTVEFSVF9fX1NDSExBQ09VTlRfX18kKGRhdGUgKyclRCAlWCcpXVxuIiA+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICAKICBlY2hvICIjIyMgU3RhcnRpbmcgIHNjSExBY291bnQgYXQgJChkYXRlICsnJUQgJVgnKSIgPj4gJExPR19ESVIvJHsxfS8kezF9XyR7Mn0ubG9nCiAgCiAgIyBpZiBbIC1kICRTQ0hMQUNPVU5UX0RJUi8kezF9X3Jlc3VsdHMgXTsgdGhlbiBybSAtciAkU0NITEFDT1VOVF9ESVIvJHsxfV9yZXN1bHRzO2ZpCiAgWyAhIC1kIFNDSExBQ09VTlRfRElSLyR7Mn0gXSAmJiBta2RpciAtcCAkU0NITEFDT1VOVF9ESVIvJHsyfQoKICBzY19obGFfY291bnQgXAogIC0tYmFtICRCQU1fRElSLyR7MX0uYmFtIFwKICAtLWNlbGwtYmFyY29kZXMgJEJBUkNPREVfRElSLyR7MX1fYmFyY29kZS50c3YgXAogIC0tb3V0LWRpciAkU0NITEFDT1VOVF9ESVIvJHsyfS8kezF9X3Jlc3VsdHMgXAogIC0tZmFzdGEtY2RzICRITEFfRElSLyR7Mn0vJHsxfV9jZHMuZmFzdGEgXAogIC0tZmFzdGEtZ2Vub21pYyAkSExBX0RJUi8kezJ9LyR7MX1fZ2VuLmZhc3RhXAogID4+ICRMT0dfRElSLyR7MX0vJHsxfV8kezJ9LmxvZyBcCiAgMj4+ICRMT0dfRElSLyR7MX0vJHsxfV8kezJ9LmxvZwoKICBwcmludGYgIiMjIyBbQ09NUExFVEVfX19TQ0hMQUNPVU5UX19fJChkYXRlICsnJUQgJVgnKV1cbiIgPj4gJExPR19ESVIvJHsxfS8kezF9XyR7Mn0ubG9nCn0KZXhwb3J0IC1mIFNDSExBQ09VTlQKCgojIERFRklORSBQSVBFTElORSBDT05UUk9MTEVSIEZVTkNUSU9OICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpQSVBFTElORSgpewogIGVjaG8gIlNUQVJUOiBzYW1wbGUgJDEgYXQgJChkYXRlICsnJUQgJVgnKSIKICBmb3IgRyBpbiBhcmNhc0hMQSBobGFtaW5lciBpbnZpdHJvIG9wdGl0eXBlIHBobGF0CiAgZG8KICAgIFsgISAtZCAkTE9HX0RJUi8kezF9IF0gJiYgbWtkaXIgLXAgJExPR19ESVIvJHsxfQogICAgSExBX1JFRkVSRU5DRSAkMSAkRwogICAgU0NITEFDT1VOVCAkMSAkRwogIGRvbmUKICBlY2hvICJDT01QTEVURTogc2FtcGxlICQxIGF0ICQoZGF0ZSArJyVEICVYJykiCn0KZXhwb3J0IC1mIFBJUEVMSU5FCgpjYXQgJEJBU0VfRElSL0JMX2Zhc3RxX2ZpbGVzLnR4dCB8IHBhcmFsbGVsIC0tZGVsYXkgMTUgLWogJFNMVVJNX05UQVNLUyAtLWpvYmxvZyAkTE9HX0RJUi9wYXJhbGxlbC5sb2cgUElQRUxJTkUge30KYGBgCgoKIyBVTUFQIHByb2plY3Rpb25zCgojIyMgQ2VsbCBjbHVzdGVycwoKYGBge3J9CnNydCA8LSByZWFkUkRTKCIvbGFicy9raGF0cmlsYWIvaG9uZ3poZW5nL3dlYmFwcHMvaXNiL3NydF9pc2IyNjAubWV0YS5yZHMiKQpjZWxscyA8LSBjKCJDRDE0IE1vbm9jeXRlIiwgIkNENCBUIiwgIkNEOCBUIiwgIk5LIiwgIkIiLCAiQ0QxNiBNb25vY3l0ZSIsICJjREMiLCAicERDIikKIyBzcnQgPC0gc3J0ICU+JSBmaWx0ZXIoY2VsbHR5cGUgJWluJSBjZWxscykKYGBgCgpgYGB7cn0KIyBnZ3Bsb3QgdGhlbWUgdG8gb3ZlcmxheSBjbHVzdGVyIGlkICNzIG9uIFVNQVAKZ2dfc3J0X3JlbGFiZWwgPC0gZnVuY3Rpb24oZGYsIHhfdmFyLCB5X3ZhciwgY29sb3JfdmFyLCBjZWxsX2ZyYWN0aW9uID0gMSl7CiAgcGx0IDwtIGRmICU+JSAKICAgIGdncGxvdChhZXMoeCA9ICEhc3ltKHhfdmFyKSwgeSA9ICEhc3ltKHlfdmFyKSwgY29sb3IgPSAhIXN5bShjb2xvcl92YXIpKSkgKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41LCBhbHBoYSA9IDAuNSkrCiAgICB0aGVtZV9idygpICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikrCiAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMiwgYWxwaGEgPSAxKSkpCiAgCiAgZyA8LSBnZ3Bsb3RfYnVpbGQocGx0KQogIAogIHBsdF9pZHMgPC0gZyRkYXRhW1sxXV0KICBncm91cF9sZXZlbHMgPC0gbGV2ZWxzKGZhY3RvcihnJHBsb3QkZGF0YVtbZyRwbG90JGxhYmVscyRjb2xvdXJdXSkpCiAgCiAgcGx0X2tleSA8LSBnJGRhdGFbWzFdXSAlPiUgCiAgICBzZWxlY3QoY29sb3VyLCBncm91cCkgJT4lIAogICAgZGlzdGluY3QoKSAlPiUgCiAgICBtdXRhdGUobGFiZWwgPSBtYXBfY2hyKGdyb3VwLCBmdW5jdGlvbih4KSBncm91cF9sZXZlbHNbeF0pKSAlPiUgCiAgICBtdXRhdGUobGFiZWwgPSBmYWN0b3IobGFiZWwsIGxldmVsID0gZ3JvdXBfbGV2ZWxzKSkgJT4lCiAgICBtdXRhdGUobGFiZWwgPSBzcHJpbnRmKCIlcykgJXMiLCAxOm4oKSwgbGFiZWwpKSAlPiUgCiAgICBzZWxlY3QoLWdyb3VwKQogIAogIHBsdF9kZiA8LSBwbHRfaWRzICU+JSAKICAgIGxlZnRfam9pbihwbHRfa2V5LCBieSA9ICJjb2xvdXIiKQogIAogIHBsdF9jZW50ZXIgPC0gcGx0X2RmICU+JSAKICAgIGdyb3VwX2J5KGxhYmVsKSAlPiUgc3VtbWFyaXNlKHggPSBtZWFuKHgpLCB5ID0gbWVhbih5KSkgJT4lCiAgICBtdXRhdGUobGFiZWwgPSBnc3ViKCIpLioiLCIiLGxhYmVsKSkKICAKICBwbHRfcmVwZWwgPC0gcGx0X2RmICU+JSAKICAgIGdncGxvdChhZXMoeD14LHk9eSxjb2xvcj1sYWJlbCkpICsKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkrCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YT1wbHRfY2VudGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbD1sYWJlbCwgIGJnLmNvbG9yPSJ3aGl0ZSIsIGJnLnI9MC4yNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiKSArCiAgICB0aGVtZV9idygpICsKICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAyKSApICkgKwogICAgbGFicyh4PXhfdmFyLCB5ID0geV92YXIsIGNvbG9yID0gY29sb3JfdmFyKSArCiAgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpCiAgcmV0dXJuKHBsdF9yZXBlbCkKfQoKcGx0X3NydCA8LSBzcnQgJT4lIAogIGZpbHRlcihjZWxsdHlwZSAlaW4lIGNlbGxzKSAlPiUgCiAgZmlsdGVyKHNhbXBsZUlEID09ICJJTkNPVjA2OS1CTCIpICU+JSAKICBnZ19zcnRfcmVsYWJlbCh4X3ZhciA9ICJVTUFQXzEiLCB5X3ZhciA9ICJVTUFQXzIiLCBjb2xvcl92YXIgPSAiY2VsbHR5cGUiLCBjZWxsX2ZyYWN0aW9uID0gMC4xKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSsgCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpKSArCiAgbGFicyh4PSJVTUFQIDEiLCB5ID0gIlVNQVAgMiIsIGNvbG9yID0gIkNlbGwgQ2x1c3RlciIpCnBsdF9zcnQKYGBgCiMjIyBBbGxlbGUgZnJlcXVlbmN5CgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA2fQpzYW1wIDwtICJJTkNPVjA2OS1CTCIKIyBzYW1wIDwtICJJTkNPVjAyOC1CTCIKZ2VuZV9zZWxlY3QgPC0gIkEiCnNjSExBY291bnRfZGlyIDwtIHNwcmludGYoIiVzL3NjSExBY291bnQiLCBpc2JfcGF0aCkKCiMgQ3JlYXRlIHRpYmJsZSBvZiBhbGwgZ2Vub3R5cGVyIGFuZCBzYW1wbGUgY29tYmluYXRpb25zCmFsbGVsZV9kYXRhIDwtIGV4cGFuZF9ncmlkKAogIGdlbm90eXBlciA9IGMoImludml0cm8iLCAiYXJjYXNITEEiLCAib3B0aXR5cGUiLCAicGhsYXQiLCAiaGxhbWluZXIiKSwKICBzYW1wbGUgPSByZWFkX2xpbmVzKAogICAgIi9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9jb3ZpZC9pc2Ivc2NITEFjb3VudC9CTF9mYXN0cV9maWxlcy50eHQiCiAgKSkgJT4lIAogIGZpbHRlcihncmVwbChzYW1wLCBzYW1wbGUpKSAlPiUgCiAgIyBJbXBvcnQgZGF0YSBiYXNlZCBvbiBzYW1wbGUgYW5kIGdlbm90eXBlcgogIG11dGF0ZShyZXN1bHRfcGF0aCA9IHNwcmludGYoIiVzL291dHB1dC8lcyIsc2NITEFjb3VudF9kaXIsIGdlbm90eXBlciksCiAgICAgICAgIGJhcmNvZGVfcGF0aCA9IHNwcmludGYoIiVzL2JhcmNvZGVzIiwgc2NITEFjb3VudF9kaXIpKSAlPiUgCiAgbXV0YXRlKGRhdGEgPSBwbWFwKGxpc3Qoc2FtcGxlLCByZXN1bHRfcGF0aCwgYmFyY29kZV9wYXRoKSwgZnVuY3Rpb24ocyxyLGIpewogICAgZGYgPC0gc2NITEFfZGF0YV9wcm9jZXNzaW5nKAogICAgICBzYW1wbGU9cywKICAgICAgcmVzdWx0X2Rpcj1yLAogICAgICBiYXJjb2RlX2Rpcj1iCiAgICApIAogIH0pKSAlPiUgdW5uZXN0KGRhdGEpCgoKYWxsZWxlX2RhdGFfcmF0aW9zIDwtIGFsbGVsZV9kYXRhICU+JSAKICBmaWx0ZXIoZ2VuZSA9PSBnZW5lX3NlbGVjdCkgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAKICBtdXRhdGUoYWxsZWxlX29yZGVyID0gZmN0X3JlY29kZShmYWN0b3IoYWxsZWxlX29yZGVyKSwgIkFsbGVsZSAxIiA9ICIxIiwgIkFsbGVsZSAyIiA9ICIyIikpCmFsbGVsZV9kYXRhCiAgCmFsbGVsZV9sYWJlbCA8LSBhbGxlbGVfZGF0YV9yYXRpb3MgJT4lIAogIHNlbGVjdChnZW5vdHlwZXIsIGFsbGVsZV9vcmRlciwgYWxsZWxlKSAlPiUgCiAgZGlzdGluY3QoKQoKcGx0IDwtIHNydCAlPiUgCiAgbGVmdF9qb2luKGFsbGVsZV9kYXRhX3JhdGlvcyAlPiUgZmlsdGVyKGdlbmUgPT0gZ2VuZV9zZWxlY3QpLCBieSA9ICJjZWxsIikgJT4lIAogIGZpbHRlcighaXMubmEoYWxsZWxlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3IgPSBhbGxlbGVfcmF0aW8pKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC41LCBhbHBoYSA9IDAuNSkrCiAgdGhlbWVfYncoKSArCiAgZmFjZXRfZ3JpZChhbGxlbGVfb3JkZXJ+Z2Vub3R5cGVyKSsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIoaGlnaCA9ICJyZWQiLCBtaWQgPSAiZ3JleTgwIiwgbG93ID0gImJsdWUiLCBtaWRwb2ludCA9IDAuNSwgbmEudmFsdWUgPSAidHJhbnNwYXJlbnQiKSArCiAgbGFicyh4PSJVTUFQIDEiLCB5PSJVTUFQIDIiLCBjb2xvciA9ICJBbGxlbGUgXG5GcmVxdWVuY3kiKSsKICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMTAsMTUpKQpwbHRfYWxsZWxlX2ZyZXEgPC0gcGx0KwogIGdlb21fbGFiZWwoZGF0YSA9IGFsbGVsZV9sYWJlbCwgYWVzKHg9LTEwLHk9MTQsIGNvbG9yID0gTlVMTCwgbGFiZWwgPSBhbGxlbGUpLCBzaXplID0gMywgaGp1c3QgPSAwKQpwbHRfYWxsZWxlX2ZyZXEKYGBgCgojIyMgTWF4aW11bSBhbGxlbGUKCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDMsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0KIyBzYW1wIDwtICJJTkNPVjA2OS1CTCIKc2FtcCA8LSAiSU5DT1YwMjItQkwiCiMgc2FtcCA8LSAiSU5DT1YwMjgtQkwiCiMgc2FtcCA8LSAiSU5DT1YwODMtQkwiCnNjSExBY291bnRfZGlyIDwtIHNwcmludGYoIiVzL3NjSExBY291bnQiLCBpc2JfcGF0aCkKCiMgQ3JlYXRlIHRpYmJsZSBvZiBhbGwgZ2Vub3R5cGVyIGFuZCBzYW1wbGUgY29tYmluYXRpb25zCmFsbGVsZV9tYXhfcmF0aW8gPC0gYWxsZWxlX2RhdGEgICU+JQogIHNlbGVjdChnZW5vdHlwZXIsIGNlbGwsIGdlbmUsIGFsbGVsZV9vcmRlciwgYWxsZWxlX3JhdGlvKSAlPiUKICAjIGdyb3VwX2J5KGdlbm90eXBlciwgY2VsbCwgYWxsZWxlX29yZGVyKSAlPiUgIG11dGF0ZSh0ZXN0ID0gbGVuZ3RoKGFsbGVsZV9vcmRlcikpCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJhbGxlbGVfb3JkZXIiLCB2YWx1ZXNfZnJvbSA9ICJhbGxlbGVfcmF0aW8iLCBuYW1lc19wcmVmaXggPSAiYWxsZWxlXyIpICU+JQogIHJvd3dpc2UoKSAlPiUKICBtdXRhdGUobWF4X3JhdGlvID0gbWF4KGFjcm9zcyhjb250YWlucygiYWxsZWxlXyIpKSwgbmEucm0gPSBUKSkgJT4lCiAgc2VsZWN0KGdlbm90eXBlciwgY2VsbCwgZ2VuZSwgbWF4X3JhdGlvKSAlPiUKICBmaWx0ZXIoZ2VuZSA9PSBnZW5lX3NlbGVjdCkgCgphbGxlbGVfbGFiZWwgPC0gYWxsZWxlX2RhdGEgJT4lIHNlbGVjdChzYW1wbGUsIGdlbm90eXBlciwgZ2VuZSwgYWxsZWxlKSAlPiUgCiAgZmlsdGVyKGdlbmUgPT0gZ2VuZV9zZWxlY3QpICU+JSAKICBzZXBhcmF0ZShzYW1wbGUsIGludG8gPSBjKCJzYW1wbGUiLCBOVUxMKSwgc2VwID0gIl8iLCBleHRyYSA9ICJkcm9wIikgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSwgZ2Vub3R5cGVyLCBnZW5lKSAlPiUgbmVzdCgpICU+JSB1bm5lc3Rfd2lkZXIoZGF0YSkgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAKICBtdXRhdGUoYWxsZWxlID0gbWFwX2NocihhbGxlbGUsIHBhc3RlLCBjb2xsYXBzZSA9ICJcbiIpKQoKcGx0X21heF9hbGxlbGUgPC0gc3J0ICU+JSAKICBsZWZ0X2pvaW4oYWxsZWxlX21heF9yYXRpbyAlPiUgZmlsdGVyKGdlbmUgPT0gIkEiKSwgYnkgPSAiY2VsbCIpICU+JSAKICAjIG11dGF0ZShnZW5vdHlwZXIgPSBmY3RfcmVsZXZlbChnZW5vdHlwZXIsICJpbnZpdHJvIikpICU+JSAKICBtdXRhdGUoZ2Vub3R5cGVyID0gcmVmb3JtYXRfaGxhX2dlbm90eXBlcihnZW5vdHlwZXIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShnZW5vdHlwZXIpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG9yID0gbWF4X3JhdGlvKSkgKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41LCBhbHBoYSA9IDAuNSkrCiAgICBnZW9tX2xhYmVsKGRhdGEgPSBhbGxlbGVfbGFiZWwsIGFlcyhjb2xvciA9IE5VTEwsIGxhYmVsID0gYWxsZWxlLCB4ID0gLUluZiwgeSA9IC1JbmYpLAogICAgICAgICAgICBoanVzdCA9IC0wLjEsIHZqdXN0ID0gLTAuMSwgc2l6ZSA9IDMsIGhqdXN0ID0gMCkgKwogICAgdGhlbWVfYncoKSArCiAgICBmYWNldF9ncmlkKC5+Z2Vub3R5cGVyKSsKICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGhpZ2ggPSAicmVkIiwgbG93ID0gImJsdWUiLCBuYS52YWx1ZSA9ICJ0cmFuc3BhcmVudCIpICsKICAgIGxhYnMoeD0iVU1BUCAxIiwgeT0iVU1BUCAyIiwgY29sb3IgPSAiTWF4aW11bSBBbGxlbGUgXG5GcmVxdWVuY3kiKSsKICAgIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkKCnBsdF9tYXhfYWxsZWxlIApgYGAKYGBge3J9CnBsdF9tYXhfYWxsZWxlIDwtIHNydCAlPiUgCiAgbGVmdF9qb2luKGFsbGVsZV9kYXRhICU+JSBmaWx0ZXIoZ2VuZSA9PSAiQSIpLCBieSA9ICJjZWxsIikKcGx0X21heF9hbGxlbGUkZ2Vub3R5cGVyICU+JSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKCkgJT4lIGxldmVscygpCmBgYAoKCgojIE1ldGEtYW5hbHlzaXMgYXBwcm9hY2gKCiMjIyBSYXRpb25hbGUgCgotIEdvYWw6IGRldGVybWluZSBhIHN1bW1hcnkgc3RhdGlzdGljIGZvciBhbGxlbGUgcmF0aW8gYWNyb3NzIGFsbCBjZWxscwotIFByb2JsZW06CiAgLSBFYWNoIGNlbGwgaW4gc2NSTkEgZXhwZXJpbWVudCBoYXMgaXRzIG93biByYXRpbyBvZiBITEEgYWxsZWxlIDEgcmVhZHMgOiBITEEgYWxsZWxlIDIgcmVhZHMKICAtIEEgd2lkZSByYW5nZSBvZiB0b3RhbCByZWFkIGNvdW50cyBtYXkgZ28gaW50byBlYWNoIGNlbGwncyByYXRpbwogIC0gU21hbGwgZGlmZmVyZW5jZSBpbiByZWFkIGNvdW50cyBmb3IgY2VsbHMgd2l0aCBsb3cgdG90YWwgcmVhZHMgY2FuIGdyZWF0bHkgYWx0ZXIgdGhlIGFsbGVsZSByYXRpbyBjb21wYXJlZCB0byBjZWxscyB3aXRoIGhpZ2ggdG90YWwgcmVhZCBjb3VudHMKICAgIC0gSS5lLiBDZWxscyB3aXRoIGxvdyByZWFkIGNvdW50cyBhcmUgbW9yZSBsaWtlbHkgdG8gaGF2ZSBpbXByZWNpc2UgYWxsZWxlIHJhdGlvcwogIC0gU2ltcGx5IGF2ZXJhZ2luZyByYXRpb3Mgd291bGQgZXF1YWxseSB3ZWlnaHQgaGlnaCBjb25maWRlbmNlLCBoaWdoIHJlYWQgY291bnQgcmF0aW9zIHdpdGggbG93IGNvbmZpZGVuY2UsIGxvdyByZWFkIHJhdGlvcwotIEFwcHJvYWNoCiAgLSBNZXRhLWFuYWx5c2lzIG1ldGhvZHMgc3BlY2lmaWNhbGx5IGFkZHJlc3MgdHlwZSBvZiBwcm9ibGVtLCB0eXBpY2FsbHkgYnkgd2VpZ2hpbmcgYW4gZWZmZWN0IGJ5IHRoZSBpbnZlcnNlIG9mIGl0cyB2YXJpYW5jZQogIC0gSW4gdGhlIHNldHRpbmcgb2YgcmF0aW9zLCBiYXNpYyBhcHByb2FjaCB3b3VsZCBiZSB0byBjb21iaW5lIGxvZy1vZGRzIHJhdGlvIG9mIGFsbGVsZXMsIHdlaWdodGVkIGJ5IGludmVyc2UgdmFyaWFuY2UKICAtIFdvdWxkIHVzZSBhIHJhbmRvbSBlZmZlY3RzIG1vZGVsIGJlY2F1c2UgZG8gbm90IGV4cGVjdCBlYWNoIGNlbGwgaW4gYSBncm91cCB3b3VsZCBoYXZlIHRoZSBzYW1lIGV4YWN0IHJhdGlvIGR1ZSB0byB2YXJpb3VzIHN0b2NoYXN0aWMgdHJhbnNjcmlwdGlvbmFsIGVmZmVjdHMKCiMjIyBDYWxjdWxhdGluZyBzdW1tYXJ5IGVmZmVjdCBzaXplcwoKLSBBbmFseXNpcyBjYW4gdGFrZSBzb21lIHRpbWUsIHNvIHJ1biBpbiBzbHVybQotIENvbnRhaW5lZCBpbiBhIHNlcGFyYXRlIHNjcmlwdCBgLi9zbHVybS9zY19tZXRhLlJgOgoKIyMjIyBDb250ZW50cyBvZiBgc2NfbWV0YS5SYAoKYGBge3IsIGV2YWwgPSBGfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtZXRhKQoKcHJvamVjdF9kaXIgPC0gIi9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9obGFfcHJvamVjdC9obGFfYmVuY2htYXJrIgpzb3VyY2Uoc3ByaW50ZigiJXMvZGF0YV9pbXBvcnRfZnVuY3Rpb25zLlIiLCBwcm9qZWN0X2RpcikpCmlzYl9wYXRoIDwtICIvbGFicy9raGF0cmlsYWIvc29sb21vbmIvY292aWQvaXNiIgpzY0hMQWNvdW50X2RpciA8LSBzcHJpbnRmKCIlcy9zY0hMQWNvdW50IiwgaXNiX3BhdGgpCgpzcnQgPC0gcmVhZFJEUygiL2xhYnMva2hhdHJpbGFiL2hvbmd6aGVuZy93ZWJhcHBzL2lzYi9zcnRfaXNiMjYwLm1ldGEucmRzIikKY2VsbHMgPC0gYygiQ0QxNCBNb25vY3l0ZSIsICJDRDQgVCIsICJDRDggVCIsICJOSyIsICJCIiwgIkNEMTYgTW9ub2N5dGUiLCAiY0RDIiwgInBEQyIpCgojIEZ1bmN0aW9uIHRvIHBlcmZvcm0gbWV0YS1hbmFseXNpcyBvbiBkYXRhZnJhbWUgd2hlcmUKIyBlYWNoIHJvdyBpcyBhIGNlbGwgYW5kIGNvbHVtbnM6CiMgYG9ic2VydmVkYCAocmVhZHMgb2YgZG9taW5hbnQgYWxsZWxlKQojIGBnZW5lX3N1bV90eXBlZGAgKHRvdGFsIGNlbGwgcmVhZHMpCiMgYGV4cGVjdGVkYCAocmVhZHMgb2Ygb25lIGFsbGVsZSBleHBlY3RlZCBpZiA1MDo1MCBhbGxlbGVfMSA6IGFsbGVsZV8yKQpzY19tZXRhIDwtIGZ1bmN0aW9uKGRmKXsKICBsIDwtIG5yb3coZGYpCiAgbSA8LSBtZXRhYmluKGV2ZW50LmUgPSBvYnNlcnZlZCwgbi5lID0gZ2VuZV9zdW1fdHlwZWQsIGV2ZW50LmMgPSBleHBlY3RlZCwgbi5jID0gZ2VuZV9zdW1fdHlwZWQsCiAgICAgICAgICAgICAgIGRhdGEgPSBkZiwKICAgICAgICAgICAgICAgbWV0aG9kID0gIkludmVyc2UiLAogICAgICAgICAgICAgICBpbmNyID0gMC4xLAogICAgICAgICAgICAgICBzbSA9ICJPUiIpCiAgZGF0YS5mcmFtZShzdW1tYXJ5KG0pJHJhbmRvbSkgJT4lIAogICAgbXV0YXRlKG5fY2VsbHMgPSBsKSAlPiUgCiAgICBzZWxlY3QoVEUsIHNlVEUsIGxvd2VyLCB1cHBlciwgbl9jZWxscykgCn0KCiMgSW1wb3J0IGRhdGEgYmFzZWQgb24gc2FtcGxlIGFuZCBnZW5vdHlwZXIKY2VsbF9zdGF0cyA8LSBleHBhbmRfZ3JpZCgKICBnZW5vdHlwZXIgPSBjKCJpbnZpdHJvIiwgImFyY2FzSExBIiwgIm9wdGl0eXBlIiwgInBobGF0IiwgImhsYW1pbmVyIiksCiAgc2FtcGxlID0gcmVhZF9saW5lcygKICAgICIvbGFicy9raGF0cmlsYWIvc29sb21vbmIvY292aWQvaXNiL3NjSExBY291bnQvQkxfZmFzdHFfZmlsZXMudHh0IgogICkpICU+JQogICMgaGVhZCg1KSAlPiUgIyBTcGVjaWZ5IGxpbWl0IHRvIG51bWJlciBvZiBtZXRhLWFuYWx5c2VzCiAgbXV0YXRlKGRhdGEgPSBtYXAyKHNhbXBsZSwgZ2Vub3R5cGVyLCBmdW5jdGlvbihzLGcpewogICAgcmVzdWx0X3BhdGggPSBzcHJpbnRmKCIlcy9vdXRwdXQvJXMiLCBzY0hMQWNvdW50X2RpciwgZykKICAgIGJhcmNvZGVfcGF0aCA9IHNwcmludGYoIiVzL2JhcmNvZGVzIiwgc2NITEFjb3VudF9kaXIpCiAgICBzY0hMQV9kYXRhX3Byb2Nlc3Npbmcoc2FtcGxlID0gcywKICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRfZGlyID0gcmVzdWx0X3BhdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyY29kZV9kaXIgPSBiYXJjb2RlX3BhdGgpCiAgfSkpICU+JSB1bm5lc3QoZGF0YSkgJT4lIAogIGZpbHRlcighaXMubmEoY2VsbCkpICU+JSAKICBtdXRhdGUoc2FtcGxlID0gZ3N1YigiX1tBLVpdWzAtOV0kIiwiIixzYW1wbGUpKSAlPiUgIyBDb25zb2xpZGF0ZSBzYW1wbGVzCiAgbGVmdF9qb2luKHNydCAlPiUgc2VsZWN0KGNlbGx0eXBlLCBjZWxsKSwgYnkgPSAiY2VsbCIpICU+JSAjIEFkZCBjZWxsdHlwZXMKICBmaWx0ZXIoY2VsbHR5cGUgJWluJSBjZWxscykgIyBLZWVwIG9ubHkgc3RhbmRhcmQgY2VsbCB0eXBlcwoKCm1ldGFfZGYgPC0gY2VsbF9zdGF0cyAlPiUgCiAgIyBLZWVwIG9ubHkgbW9zdCBleHByZXNzZWQgYWxsZWxlIChvciByYW5kb20gaWYgNTA6NTApCiAgZ3JvdXBfYnkoc2FtcGxlLCBnZW5vdHlwZXIsIGdlbmUsIGNlbGwpICU+JSAKICBzbGljZV9tYXgob3JkZXJfYnkgPSBhbGxlbGVfcmF0aW8sIG4gPSAxLCB3aXRoX3RpZXMgPSBGKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICAjIEZpbGwgb3V0IGNvbnRpbmdlbmN5IHRhYmxlCiAgbXV0YXRlKGNvbXBsZW1lbnQgPSBnZW5lX3N1bV90eXBlZCAtIGNvdW50LCAKICAgICAgICAgZXhwZWN0ZWQgPSAwLjUqZ2VuZV9zdW1fdHlwZWQpICU+JSAKICByZW5hbWUob2JzZXJ2ZWQgPSBjb3VudCkgJT4lIAogIHNlbGVjdChzYW1wbGUsIGdlbm90eXBlciwgY2VsbHR5cGUsIGdlbmUsIG9ic2VydmVkLCBleHBlY3RlZCwgZ2VuZV9zdW1fdHlwZWQpICU+JSAKICBncm91cF9ieShzYW1wbGUsIGdlbm90eXBlciwgY2VsbHR5cGUsIGdlbmUpICU+JQogICMgTmVzdCBhbmQgcnVuIG1ldGEtYW5hbHlzaXMKICBuZXN0KCkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUoZGF0YSA9IG1hcChkYXRhLGZ1bmN0aW9uKHgpIHtzY19tZXRhKHgpfSkpICU+JQogIHVubmVzdChkYXRhKQoKd3JpdGVfY3N2KG1ldGFfZGYsIHNwcmludGYoIiVzL3NsdXJtL21ldGFfYW5hbHlzaXNfcmVzdWx0cy5jc3YiLCBwcm9qZWN0X2RpcikpCmBgYAoKIyMjIFNpbmdsZSBzYW1wbGUgYW5hbHlzaXMKCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KbWV0YV9kZiA8LSByZWFkX2NzdigiLi9zbHVybS9tZXRhX2FuYWx5c2lzX3Jlc3VsdHMuY3N2IikgCm1ldGFfZGYKYGBgCmBgYHtyfQojIFNpbmdsZSBjZWxsdHlwZSBhbmQgZ2VuZQpzYW1wIDwtICJJTkNPVjA2OS1CTCIKIyBzYW1wIDwtICJJTkNPVjAyMi1CTCIKcGx0X21ldGEgPC0gbWV0YV9kZiAlPiUgCiAgZmlsdGVyKHNhbXBsZSA9PSBzYW1wKSAlPiUgCiAgZmlsdGVyKGNlbGx0eXBlID09ICJOSyIsIGdlbmUgPT0gIkEiKSAlPiUgCiAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGdlbm90eXBlciwgeSA9IFRFLCB5bWluID0gbG93ZXIsIHltYXggPSB1cHBlcikpKwogIGdlb21fcG9pbnQoKSsKICBnZW9tX2Vycm9yYmFyKCkrCiAgdGhlbWVfYncoKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLE5BKSkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogIGxhYnMoeSA9ICJMb2ctT2RkcyByYXRpbyBvZiBkb21pbmFudCBhbGxlbGUiLCB4PSBOVUxMKQpwbHRfbWV0YQpgYGAKYGBge3J9CnNhbXAgPC0gIklOQ09WMDY5LUJMIgpzYW1wbGVzIDwtIHVuaXF1ZShtZXRhX2RmJHNhbXBsZSkKZm9yIChpIGluIDE6bGVuZ3RoKHNhbXBsZXMpKXsKcGx0X21ldGEgPC0gbWV0YV9kZiAlPiUgCiAgZmlsdGVyKHNhbXBsZSA9PSBzYW1wbGVzW2ldKSAlPiUgCiAgZmlsdGVyKGNlbGx0eXBlID09ICJDRDE0IE1vbm9jeXRlIiwgZ2VuZSA9PSAiQSIpICU+JSAKICBtdXRhdGUoZ2Vub3R5cGVyID0gcmVmb3JtYXRfaGxhX2dlbm90eXBlcihnZW5vdHlwZXIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZ2Vub3R5cGVyLCB5ID0gVEUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyKSkrCiAgZ2VvbV9wb2ludCgpKwogIGdlb21fZXJyb3JiYXIoKSsKICB0aGVtZV9idygpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsTkEpKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgbGFicyh5ID0gIkxvZy1PZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwpICsKICBnZ3RpdGxlKHNhbXBsZXNbaV0pCiAgcHJpbnQocGx0X21ldGEpCn0KYGBgCgoKCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDR9CiMgQWxsIGNlbGx0eXBlcyBhbmQgZ2VuZXMKbWV0YV9kZiAlPiUgCiAgbXV0YXRlKAogICAgY2VsbHR5cGUgPSBmYWN0b3IoY2VsbHR5cGUsIGxldmVscyA9IGMoCiAgICAiY0RDIiwgIkNEMTQgTW9ub2N5dGUiLCAiQiIsICJwREMiLCAiQ0QxNiBNb25vY3l0ZSIsICJDRDggVCIsICJDRDQgVCIsICJOSyIpKSkgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAKICBtdXRhdGUoZ2VuZSA9IHJlZm9ybWF0X2hsYV9sb2NpKGdlbmUpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY2VsbHR5cGUsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIsIGZpbGwgPSBjZWxsdHlwZSkpKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yNSkrCiAgICBnZW9tX2Vycm9yYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgd2lkdGggPTAuNSkrCiAgICB0aGVtZV9idygpKwogICAgZmFjZXRfZ3JpZChnZW5lfmdlbm90eXBlciwgc2NhbGVzID0gImZyZWVfeSIpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogICAgbGFicyh5ID0gIkxvZy1PZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwsIGZpbGwgPSAiQ2VsbCB0eXBlIikgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCgptZXRhX2RmICU+JSAKICBtdXRhdGUoCiAgICBjZWxsdHlwZSA9IGZhY3RvcihjZWxsdHlwZSwgbGV2ZWxzID0gYygKICAgICJjREMiLCAiQ0QxNCBNb25vY3l0ZSIsICJCIiwgInBEQyIsICJDRDE2IE1vbm9jeXRlIiwgIkNEOCBUIiwgIkNENCBUIiwgIk5LIikpKSAlPiUgCiAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSkgJT4lIAogIG11dGF0ZShnZW5lID0gcmVmb3JtYXRfaGxhX2xvY2koZ2VuZSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBnZW5vdHlwZXIsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIsIGZpbGwgPSBjZWxsdHlwZSkpKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yNSkrCiAgICBnZW9tX2Vycm9yYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgd2lkdGggPTAuNSkrCiAgICB0aGVtZV9idygpKwogICAgZmFjZXRfZ3JpZChnZW5lfmNlbGx0eXBlLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgICBsYWJzKHkgPSAiTG9nLU9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCwgZmlsbCA9ICJDZWxsIHR5cGUiKSArCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKYGBgCgoKCiMjIyBNdWx0aS1zYW1wbGUgYW5hbHlzaXMKCmBgYHtyLCBtZXNzYWdlID0gRn0KbWV0YV9kZiA8LSByZWFkX2NzdigiLi9zbHVybS9tZXRhX2FuYWx5c2lzX3Jlc3VsdHMuY3N2IikgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlciksCiAgICAgICAgIGNlbGx0eXBlID0gZmFjdG9yKGNlbGx0eXBlLCBsZXZlbHMgPSBjKAogICAgICAgICAgImNEQyIsICJDRDE0IE1vbm9jeXRlIiwgIkIiLCAicERDIiwgIkNEMTYgTW9ub2N5dGUiLCAiQ0Q4IFQiLCAiQ0Q0IFQiLCAiTksiKSkpCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNiwgd2FybmluZyA9IEZ9Cm1ldGFfZGYgJT4lIAogIGdncGxvdChhZXMoeD1jZWxsdHlwZSx5PVRFLCBmaWxsID0gY2VsbHR5cGUpKSsKICBnZW9tX3Zpb2xpbigpKwogIGdlb21faml0dGVyKGFscGhhID0gMC4yLCBzaXplID0gMC4yKSsKICBzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIHN0YXQ9ICJwb2ludCIpKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsIGdlb209ImVycm9yYmFyIikrCiAgZmFjZXRfZ3JpZChnZW5lfmdlbm90eXBlcikrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgbGFicyh5ID0gIkxvZy1PZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwsIGZpbGwgPSAiQ2VsbCB0eXBlIikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKQoKbWV0YV9kZiAlPiUgCiAgZ2dwbG90KGFlcyh4PWdlbm90eXBlcix5PVRFLCBmaWxsID0gY2VsbHR5cGUpKSsKICBnZW9tX3Zpb2xpbigpKwogIGdlb21faml0dGVyKGFscGhhID0gMC4yLCBzaXplID0gMC4yKSsKICBzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIHN0YXQ9ICJwb2ludCIpKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsIGdlb209ImVycm9yYmFyIikrCiAgZmFjZXRfZ3JpZChnZW5lfmNlbGx0eXBlKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBsYWJzKHkgPSAiTG9nLU9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCwgZmlsbCA9ICJDZWxsIHR5cGUiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCmBgYAoKIyMjIENvcnJlbGF0aW9uIGFuYWx5c2lzCgpgYGB7ciwgbWVzc2FnZSA9IEYsIHdhcm5pbmc9Rn0KbWV0YV9kZiAlPiUgCiAgZmlsdGVyKGdlbmUgPT0gIkEiLCBjZWxsdHlwZSA9PSAiY0RDIikgJT4lIAogIHNlbGVjdChzYW1wbGUsIGdlbm90eXBlciwgVEUpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gImdlbm90eXBlciIsIHZhbHVlc19mcm9tID0gIlRFIikgJT4lIAogIHNlbGVjdCgtc2FtcGxlKSAlPiUgCiAgR0dhbGx5OjpnZ3BhaXJzKHByb2dyZXNzID0gRkFMU0UpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nPUZ9CmFjY3VyYWN5X2RmIDwtIHJlYWRSRFMoImlzYl9hY2N1cmFjeV9kcmIzNDVfZmlsdGVyZWQuUkRTIikgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAKICBzZWxlY3Qoc2FtcGxlLCBnZW5lPWxvY3VzLCBnZW5vdHlwZXIsIGFjY3VyYWN5KSAlPiUgCiAgZGlzdGluY3QoKQpmb3IgKGkgaW4gYygwLDEpKXsKICBzdXBwcmVzc1dhcm5pbmdzKHsKICBwbHQgPC0gbWV0YV9kZiAlPiUgCiAgICB1bmdyb3VwKCkgJT4lIAogICAgZmlsdGVyKGdlbmUgPT0gIkEiLCBjZWxsdHlwZSA9PSAiY0RDIikgJT4lIAogICAgbGVmdF9qb2luKGFjY3VyYWN5X2RmLCBieSA9IGMoInNhbXBsZSIsICJnZW5lIiwgImdlbm90eXBlciIpKSAlPiUgCiAgICBmaWx0ZXIoYWNjdXJhY3kgPT0gaSB8IGdlbm90eXBlciA9PSAiR3JvdW5kIHRydXRoIikgJT4lIAogICAgIyBkcm9wX25hKGFjY3VyYWN5KSAlPiUgCiAgICBzZWxlY3Qoc2FtcGxlLCBnZW5vdHlwZXIsIFRFKSAlPiUgCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gImdlbm90eXBlciIsIHZhbHVlc19mcm9tID0gIlRFIikgJT4lIAogICAgc2VsZWN0KC1zYW1wbGUpICU+JSAKICAgIEdHYWxseTo6Z2dwYWlycyhwcm9ncmVzcyA9IEZBTFNFKSArCiAgICB0aGVtZV9idygpICsKICAgIGdndGl0bGUoc3ByaW50ZigiQ29ycmVsYXRpb24gb2YgYWxsZWxlIHJhdGlvcyB3aGVyZSBhY2N1cmFjeSA9ICVzIiwgaSkpCiAgcHJpbnQocGx0KQogIH0pCn0KYGBgCgpgYGB7ciwgd2FybmluZyA9IEZ9CmNvcnJfZGYgPC0gbWV0YV9kZiAlPiUgCiAgc2VsZWN0KHNhbXBsZSwgZ2Vub3R5cGVyLCBjZWxsdHlwZSwgZ2VuZSwgVEUpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gImdlbm90eXBlciIsIHZhbHVlc19mcm9tID0gIlRFIikgJT4lIAogIHBpdm90X2xvbmdlcihjKGFyY2FzSExBLCBITEFtaW5lciwgT3B0aVR5cGUsIFBITEFUKSwgbmFtZXNfdG8gPSAiZ2Vub3R5cGVyIiwgdmFsdWVzX3RvID0gIlRFIikgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpCmNvcnJfZGYgJT4lIAogIGdncGxvdChhZXMoeD1gR3JvdW5kIHRydXRoYCwgeT1URSkpKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkrCiAgZmFjZXRfZ3JpZChnZW5lIH4gZ2Vub3R5cGVyKSArCiAgdGhlbWVfYncoKSArCiAgZ2dwdWJyOjpzdGF0X2NvcihhZXMobGFiZWwgPSAuLnJyLmxhYmVsLi4pLCBsYWJlbC54Lm5wYyA9ICJsZWZ0IiwgbGFiZWwueS5ucGMgPSAidG9wIiwgZ2VvbSA9ICJsYWJlbCIpCmBgYAoKYGBge3J9CmZvciAoaSBpbiBjKDAsMSkpewogIHN1cHByZXNzV2FybmluZ3MoewogIHBsdCA8LSBjb3JyX2RmICU+JSAKICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAjIGZpbHRlcihnZW5lID09ICJBIiwgY2VsbHR5cGUgPT0gImNEQyIpICU+JSAKICAgIGxlZnRfam9pbihhY2N1cmFjeV9kZiwgYnkgPSBjKCJzYW1wbGUiLCAiZ2VuZSIsICJnZW5vdHlwZXIiKSkgJT4lIAogICAgZmlsdGVyKGFjY3VyYWN5ID09IGkpICU+JSAKICAgIGdncGxvdChhZXMoeD1gR3JvdW5kIHRydXRoYCwgeT1URSkpKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41KSsKICAgIGZhY2V0X2dyaWQoZ2VuZSB+IGdlbm90eXBlcikgKwogICAgdGhlbWVfYncoKSArCiAgICBnZ3B1YnI6OnN0YXRfY29yKGFlcyhsYWJlbCA9IC4ucnIubGFiZWwuLiksIGxhYmVsLngubnBjID0gImxlZnQiLCBsYWJlbC55Lm5wYyA9ICJ0b3AiLCBnZW9tID0gImxhYmVsIikgKwogICAgICBnZ3RpdGxlKHNwcmludGYoIkNvcnJlbGF0aW9uIG9mIGFsbGVsZSByYXRpb3Mgd2hlcmUgYWNjdXJhY3kgPSAlcyIsIGkpKSArCiAgICBsYWJzKHkgPSAiUHJlZGljdGVkIGdlbm90eXBlIEhMQSBhbGxlbGUgbG9nLW9kZHMgcmF0aW8iLCB4ID0gIkdyb3VuZCB0cnV0aCBnZW5vdHlwZSBITEEgYWxsZWxlIGxvZy1vZGRzIHJhdGlvIikKICBhc3NpZ24oc3ByaW50ZigicGx0X21ldGFfY29ycl8lcyIsIGkpLCBwbHQpCiAgcHJpbnQocGx0KQogIH0pCn0KCmBgYApgYGB7cn0KcGx0X21ldGFfY29ycl9hYmJyZXYgPC0gY29ycl9kZiAlPiUgCiAgbGVmdF9qb2luKGFjY3VyYWN5X2RmLCBieSA9IGMoInNhbXBsZSIsICJnZW5lIiwgImdlbm90eXBlciIpKSAlPiUgCiAgZmlsdGVyKGdlbmUgPT0gIkEiLCBhY2N1cmFjeSAlaW4lIGMoMCwxKSkgJT4lIAogIGdncGxvdChhZXMoeD1gR3JvdW5kIHRydXRoYCwgeT1URSkpKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41KSsKICAgIGZhY2V0X2dyaWQoYWNjdXJhY3kgfiBnZW5vdHlwZXIsIGxhYmVsbGVyID0gbGFiZWxsZXIoYWNjdXJhY3kgPSBmdW5jdGlvbih4KSBzcHJpbnRmKCJBY2N1cmFjeTogJXMiLCB4KSkpICsKICAgIHRoZW1lX2J3KCkgKwogICAgZ2dwdWJyOjpzdGF0X2NvcihhZXMobGFiZWwgPSAuLnJyLmxhYmVsLi4pLCBsYWJlbC54Lm5wYyA9ICJsZWZ0IiwgbGFiZWwueS5ucGMgPSAidG9wIiwgZ2VvbSA9ICJsYWJlbCIpICsKICAgIGxhYnMoeSA9ICJMb2ctb2RkcyByYXRpbyB1c2luZyBwcmVkaWN0ZWQgZ2Vub3R5cGUiLCB4ID0gIkxvZy1vZGRzIHJhdGlvIHVzaW5nIGdyb3VuZCB0cnV0aCBnZW5vdHlwZXIiKQpwbHRfbWV0YV9jb3JyX2FiYnJldgpgYGAKCgojIyMgQnkgc2V2ZXJpdHkKCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDYsIHdhcm5pbmcgPSBGfQptZXRhX2RmICU+JSAKICBmaWx0ZXIoZ2Vub3R5cGVyID09ICJHcm91bmQgdHJ1dGgiKSAlPiUgCiAgbGVmdF9qb2luKAogICAgc3J0ICU+JSAKICAgICAgc2VsZWN0KHNhbXBsZSA9IHNhbXBsZUlELCBzZXZlcml0eSkgJT4lIAogICAgICBkaXN0aW5jdCgpLAogICAgYnkgPSAic2FtcGxlIgogICkgJT4lIAogIGdncGxvdChhZXMoeD1zZXZlcml0eSx5PVRFLCBmaWxsID0gY2VsbHR5cGUpKSsKICAgIGdlb21fdmlvbGluKCkrCiAgICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuMiwgc2l6ZSA9IDAuMikrCiAgICBzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIHN0YXQ9ICJwb2ludCIpKwogICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbT0iZXJyb3JiYXIiKSsKICAgIGZhY2V0X2dyaWQoZ2VuZX5jZWxsdHlwZSkrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogICAgbGFicyh5ID0gIkxvZy1PZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwsIGZpbGwgPSAiQ2VsbCB0eXBlIikgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCmBgYAoKYGBge3J9Cm1ldGFfZGYgJT4lIAogIGZpbHRlcihnZW5vdHlwZXIgPT0gIkdyb3VuZCB0cnV0aCIpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBzcnQgJT4lIAogICAgICBzZWxlY3Qoc2FtcGxlID0gc2FtcGxlSUQsIHNldmVyaXR5KSAlPiUgCiAgICAgIGRpc3RpbmN0KCksCiAgICBieSA9ICJzYW1wbGUiCiAgKSAlPiUgCiAgbXV0YXRlKHNldmVyaXR5ID0gYXMubnVtZXJpYyhzZXZlcml0eSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzZXZlcml0eSwgeSA9IFRFKSkgKwogIGdlb21fcG9pbnQoKSArIAogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIpKwogIGZhY2V0X3dyYXAofmNlbGx0eXBlKSsKICB0aGVtZV9idygpIApgYGAKCiMgUGxvdHMgZm9yIGZpZ3VyZXMKCiMgQXNzZW1ibGUgcGxvdApgYGB7ciwgZmlnLndpZHRoID0gMTQsIGZpZy5oZWlnaHQgPSAxMH0KIyBwbHRfYWxsZWxlX2ZyZXFfbGdkIDwtIGNvd3Bsb3Q6OmdldF9sZWdlbmQocGx0X2FsbGVsZV9mcmVxKQojIHBsdF9tYXhfYWxsZWxlX2xnZCA8LSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9tYXhfYWxsZWxlKQpjb2xfMSA8LSBwbG90X2dyaWQoCiAgcGx0X2FsbGVsZV9mcmVxLAogIHBsdF9tYXhfYWxsZWxlLAogIG5jb2wgPSAxLAogIHJlbF9oZWlnaHRzID0gYyg1LDMpLAogIGFsaWduID0gInYiLCBheGlzID0gImxyIiwKICBsYWJlbHMgPSBMRVRURVJTWzE6Ml0KKQoKY29sXzIgPC0gcGxvdF9ncmlkKAogIHBsdF9zcnQsCiAgcGx0X21ldGEsCiAgbmNvbCA9IDEsCiAgYWxpZ24gPSAidiIsIGF4aXMgPSAibHIiLAogIGxhYmVscyA9IExFVFRFUlNbMzo0XSwKICBoanVzdCA9IDAuNQopCnJvd18xIDwtIHBsb3RfZ3JpZCgKICBjb2xfMSwKICBjb2xfMiwKICBucm93ID0gMSwKICByZWxfd2lkdGhzID0gYyg2LDMpCikKcm93XzIgPC0gcGxvdF9ncmlkKAogIHBsdF9tZXRhX2NvcnJfMCArZ2d0aXRsZShOVUxMKSwKICBwbHRfbWV0YV9jb3JyXzEgK2dndGl0bGUoTlVMTCksCiAgbGFiZWxzID0gTEVUVEVSU1s1OjZdLAogIG5jb2wgPSAyCikKcGxvdF9ncmlkKAogIHJvd18xLAogIHJvd18yLAogIHJlbF9oZWlnaHRzID0gYygzLDIpLAogIG5jb2wgPSAxCikKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gMTQsIGZpZy5oZWlnaHQgPSA2fQpjb2xfMSA8LSBwbG90X2dyaWQoCiAgcGx0X3NydCwKICBwbHRfbWV0YSwKICBuY29sID0gMSwKICBhbGlnbiA9ICJ2IiwgYXhpcyA9ICJsciIsCiAgbGFiZWxzID0gTEVUVEVSU1tjKDEsMyldLAogIGxhYmVsX3ggPSAtMC4wNQopCgpjb2xfMiA8LSBwbG90X2dyaWQoCiAgcGx0X21heF9hbGxlbGUsCiAgcGx0X21ldGFfY29ycl9hYmJyZXYsCiAgbmNvbCA9IDEsCiAgcmVsX2hlaWdodHMgPSBjKDMsNSksCiAgYWxpZ24gPSAidiIsIGF4aXMgPSAibHIiLAogIGxhYmVscyA9IExFVFRFUlNbYygyLDQpXSwKICBsYWJlbF94ID0gLTAuMDUKKQoKcGxvdF9ncmlkKAogIE5VTEwsCiAgY29sXzEsCiAgY29sXzIsCiAgbnJvdyA9IDEsCiAgcmVsX3dpZHRocyA9IGMoMC4yNSwzLDYpCikKCgpgYGAKCiMgT2xkIHdvcmsKCjwhLS0gYGBge3J9IC0tPgo8IS0tIHNjX21ldGEgPC0gZnVuY3Rpb24oZGYpeyAtLT4KPCEtLSAgIG0gPC0gbWV0YWJpbihldmVudC5lID0gb2JzZXJ2ZWQsIG4uZSA9IGdlbmVfc3VtX3R5cGVkLCBldmVudC5jID0gZXhwZWN0ZWQsIG4uYyA9IGdlbmVfc3VtX3R5cGVkLCAtLT4KPCEtLSAgICAgICAgIGRhdGEgPSBkZiwgLS0+CjwhLS0gICAgICAgICBtZXRob2QgPSAiSW52ZXJzZSIsIC0tPgo8IS0tICAgICAgICAgaW5jciA9IDAuMSwgLS0+CjwhLS0gICAgICAgICBzbSA9ICJPUiIpIC0tPgo8IS0tICAgZGF0YS5mcmFtZShzdW1tYXJ5KG0pJHJhbmRvbSkgJT4lICAtLT4KPCEtLSAgICAgc2VsZWN0KFRFLCBzZVRFLCBsb3dlciwgdXBwZXIpICU+JSAgLS0+CjwhLS0gICAgIG11dGF0ZV9hbGwoZXhwKSAtLT4KPCEtLSB9IC0tPgo8IS0tIGBgYCAtLT4KCgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBzYW1wIDwtICJJTkNPVjFbMC0yXVswLTldLUJMIiAtLT4KPCEtLSB4IDwtIHRpYmJsZShnZW5vdHlwZXIgPSBjKCJpbnZpdHJvIiwgImFyY2FzSExBIiwgIm9wdGl0eXBlIiwgInBobGF0IiwgImhsYW1pbmVyIikpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoZGF0YSA9IG1hcChnZW5vdHlwZXIsIGZ1bmN0aW9uKHgpIHN1cHByZXNzTWVzc2FnZXMocmVhZF90c3YoIi4uLy4uL2NvdmlkL2lzYi9zY0hMQWNvdW50L0JMX2Zhc3RxX2ZpbGVzLnR4dCIsIGNvbF9uYW1lcyA9ICJzYW1wbGUiKSkpKSAlPiUgIC0tPgo8IS0tICAgdW5uZXN0KGRhdGEpICU+JSAgLS0+CjwhLS0gICBmaWx0ZXIoZ3JlcGwoc2FtcCwgc2FtcGxlKSkgJT4lICAtLT4KPCEtLSAgICMgSW1wb3J0IGRhdGEgYmFzZWQgb24gc2FtcGxlIGFuZCBnZW5vdHlwZXIgLS0+CjwhLS0gICBtdXRhdGUocmVzdWx0X3BhdGggPSBzcHJpbnRmKCIlcy9vdXRwdXQvJXMiLHNjSExBY291bnRfZGlyLCBnZW5vdHlwZXIpLCAtLT4KPCEtLSAgICAgICAgICBiYXJjb2RlX3BhdGggPSBzcHJpbnRmKCIlcy9iYXJjb2RlcyIsIHNjSExBY291bnRfZGlyKSkgJT4lICAtLT4KPCEtLSAgICMgaGVhZCgyKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoZGF0YSA9IHBtYXAobGlzdChzYW1wbGUsIHJlc3VsdF9wYXRoLCBiYXJjb2RlX3BhdGgpLCBmdW5jdGlvbihzLHIsYil7IC0tPgo8IS0tICAgICBzY0hMQV9kYXRhX3Byb2Nlc3NpbmcoIC0tPgo8IS0tICAgICAgIHNhbXBsZT1zLCAtLT4KPCEtLSAgICAgICByZXN1bHRfZGlyPXIsIC0tPgo8IS0tICAgICAgIGJhcmNvZGVfZGlyPWIgLS0+CjwhLS0gICAgICkgLS0+CjwhLS0gICB9KSkgJT4lIHVubmVzdChkYXRhKSAtLT4KPCEtLSB4IC0tPgo8IS0tIHkgPC0geCAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKGNlbGwgJWluJSBjZWxsX2xpc3QpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoc2FtcGxlID0gZ3N1YigiX1tBLVpdWzAtOV0kIiwiIixzYW1wbGUpKSAlPiUgIC0tPgo8IS0tICAgIyAjIGZpbHRlcihuX2FsbGVsZXNfb2JzZXJ2ZWQgPT0gMiwgZ3JlcGwoIl5EW1BRUl0iLCBnZW5lKSwgc2FtcGxlSUQgJWluJSBjKCJJTkNPVjAwMy1BQyIsICJJTkNPVjAyNC1BQyIpKSAlPiUgIC0tPgo8IS0tICAgIyBzZWxlY3QoY2VsbCwgbG9jdXMsIGNvdW50LCBnZW5lX3N1bV90eXBlZCwgY2VsbHR5cGUpICU+JSAgLS0+CjwhLS0gICAjIGdyb3VwX2J5KHNldmVyaXR5LCBjZWxsdHlwZSwgZ2VuZSkgJT4lICAtLT4KPCEtLSAgIGZpbHRlcihnZW5lID09ICJBIikgJT4lICAtLT4KPCEtLSAgIGdyb3VwX2J5KHNhbXBsZSwgZ2Vub3R5cGVyKSAlPiUgIC0tPgo8IS0tICAgc2FtcGxlX24oNTAwLCByZXBsYWNlID0gVCkgJT4lIC0tPgo8IS0tICAgbXV0YXRlKGNvbXBsZW1lbnQgPSBnZW5lX3N1bV90eXBlZCAtIGNvdW50LCBleHBlY3RlZCA9IDAuNSpnZW5lX3N1bV90eXBlZCkgJT4lICAtLT4KPCEtLSAgIHJvd3dpc2UoKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKG9ic2VydmVkID0gbWF4KGFjcm9zcyhjKGNvdW50LCBjb21wbGVtZW50KSkpKSAlPiUgIC0tPgo8IS0tICAgZ3JvdXBfYnkoc2FtcGxlLCBnZW5vdHlwZXIpICU+JSAgLS0+CjwhLS0gICBuZXN0KCkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gbWFwKGRhdGEsIHNjX21ldGEpKSAlPiUgIC0tPgo8IS0tICAgdW5uZXN0KGRhdGEpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3IsIGZpZy53aWR0aCA9IDI0LCBmaWcuaGVpZ2h0ID0gNH0gLS0+CjwhLS0geSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoZ2Vub3R5cGVyID0gZmFjdG9yKGdlbm90eXBlciwgbGV2ZWxzID0gYygiaGxhbWluZXIiLCJwaGxhdCIsIm9wdGl0eXBlIiwiYXJjYXNITEEiLCJpbnZpdHJvIikpKSAlPiUgIC0tPgo8IS0tICAgZ2dwbG90KGFlcyh4ID0gZ2Vub3R5cGVyLCB5ID0gVEUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyKSkrIC0tPgo8IS0tICAgZ2VvbV9wb2ludCgpKyAtLT4KPCEtLSAgIGdlb21fZXJyb3JiYXIoKSsgLS0+CjwhLS0gICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsgLS0+CjwhLS0gICBmYWNldF9ncmlkKC5+c2FtcGxlLCBzY2FsZXMgPSAiZnJlZSIpKyAtLT4KPCEtLSAgIHRoZW1lX2J3KCkrIC0tPgo8IS0tICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsgLS0+CjwhLS0gICBjb29yZF9mbGlwKCkgKyAtLT4KPCEtLSAgIGxhYnMoeSA9ICJPZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwpIC0tPgo8IS0tIGBgYCAtLT4KCgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBzYW1wIDwtICJJTkNPVjA2OS1CTCIgLS0+CjwhLS0gY2VsbF9saXN0IDwtIHNydCAlPiUgZmlsdGVyKGNlbGx0eXBlID09ICJjREMiKSAlPiUgcHVsbChjZWxsKSAtLT4KPCEtLSB4IDwtIHRpYmJsZShnZW5vdHlwZXIgPSBjKCJpbnZpdHJvIiwgImFyY2FzSExBIiwgIm9wdGl0eXBlIiwgInBobGF0IiwgImhsYW1pbmVyIikpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoZGF0YSA9IG1hcChnZW5vdHlwZXIsIGZ1bmN0aW9uKHgpIHN1cHByZXNzTWVzc2FnZXMocmVhZF90c3YoIi4uLy4uL2NvdmlkL2lzYi9zY0hMQWNvdW50L0JMX2Zhc3RxX2ZpbGVzLnR4dCIsIGNvbF9uYW1lcyA9ICJzYW1wbGUiKSkpKSAlPiUgIC0tPgo8IS0tICAgdW5uZXN0KGRhdGEpICU+JSAgLS0+CjwhLS0gICBmaWx0ZXIoZ3JlcGwoc2FtcCwgc2FtcGxlKSkgJT4lICAtLT4KPCEtLSAgICMgSW1wb3J0IGRhdGEgYmFzZWQgb24gc2FtcGxlIGFuZCBnZW5vdHlwZXIgLS0+CjwhLS0gICBtdXRhdGUocmVzdWx0X3BhdGggPSBzcHJpbnRmKCIlcy9vdXRwdXQvJXMiLHNjSExBY291bnRfZGlyLCBnZW5vdHlwZXIpLCAtLT4KPCEtLSAgICAgICAgICBiYXJjb2RlX3BhdGggPSBzcHJpbnRmKCIlcy9iYXJjb2RlcyIsIHNjSExBY291bnRfZGlyKSkgJT4lICAtLT4KPCEtLSAgICMgaGVhZCgyKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoZGF0YSA9IHBtYXAobGlzdChzYW1wbGUsIHJlc3VsdF9wYXRoLCBiYXJjb2RlX3BhdGgpLCBmdW5jdGlvbihzLHIsYil7IC0tPgo8IS0tICAgICBzY0hMQV9kYXRhX3Byb2Nlc3NpbmcoIC0tPgo8IS0tICAgICAgIHNhbXBsZT1zLCAtLT4KPCEtLSAgICAgICByZXN1bHRfZGlyPXIsIC0tPgo8IS0tICAgICAgIGJhcmNvZGVfZGlyPWIgLS0+CjwhLS0gICAgICkgLS0+CjwhLS0gICB9KSkgJT4lIHVubmVzdChkYXRhKSAtLT4KPCEtLSB5IDwtIHggJT4lICAtLT4KPCEtLSAgIGZpbHRlcihjZWxsICVpbiUgY2VsbF9saXN0KSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKHNhbXBsZSA9IGdzdWIoIl9bQS1aXVswLTldJCIsIiIsc2FtcGxlKSkgJT4lICAtLT4KPCEtLSAgIGZpbHRlcihnZW5lID09ICJBIikgJT4lICAtLT4KPCEtLSAgIGdyb3VwX2J5KHNhbXBsZSwgZ2Vub3R5cGVyKSAlPiUgIC0tPgo8IS0tICAgc2FtcGxlX24oNTAwLCByZXBsYWNlID0gVCkgJT4lIC0tPgo8IS0tICAgbXV0YXRlKGNvbXBsZW1lbnQgPSBnZW5lX3N1bV90eXBlZCAtIGNvdW50LCBleHBlY3RlZCA9IDAuNSpnZW5lX3N1bV90eXBlZCkgJT4lICAtLT4KPCEtLSAgIHJvd3dpc2UoKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKG9ic2VydmVkID0gbWF4KGFjcm9zcyhjKGNvdW50LCBjb21wbGVtZW50KSkpKSAlPiUgIC0tPgo8IS0tICAgZ3JvdXBfYnkoc2FtcGxlLCBnZW5vdHlwZXIpICU+JSAgLS0+CjwhLS0gICBuZXN0KCkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gbWFwKGRhdGEsIHNjX21ldGEpKSAlPiUgIC0tPgo8IS0tICAgdW5uZXN0KGRhdGEpIC0tPgo8IS0tIHBsdF9tZXRhIDwtIHkgJT4lICAtLT4KPCEtLSAgIHVuZ3JvdXAoKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSkgJT4lICAtLT4KPCEtLSAgIGdncGxvdChhZXMoeCA9IGdlbm90eXBlciwgeSA9IFRFLCB5bWluID0gbG93ZXIsIHltYXggPSB1cHBlcikpKyAtLT4KPCEtLSAgIGdlb21fcG9pbnQoKSsgLS0+CjwhLS0gICBnZW9tX2Vycm9yYmFyKCkrIC0tPgo8IS0tICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikrIC0tPgo8IS0tICAgdGhlbWVfYncoKSsgLS0+CjwhLS0gICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArIC0tPgo8IS0tICAgbGFicyh5ID0gIk9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCkgLS0+CjwhLS0gcGx0X21ldGEgICAtLT4KPCEtLSBgYGAgLS0+CjwhLS0gIyMjIEFsbCBjbHVzdGVycyAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIHNhbXAgPC0gIklOQ09WMDY5LUJMIiAtLT4KPCEtLSBjZWxsX2xpc3QgPC0gc3J0ICU+JSBmaWx0ZXIoY2VsbHR5cGUgPT0gImNEQyIpICU+JSBwdWxsKGNlbGwpIC0tPgo8IS0tIHggPC0gdGliYmxlKGdlbm90eXBlciA9IGMoImludml0cm8iLCAiYXJjYXNITEEiLCAib3B0aXR5cGUiLCAicGhsYXQiLCAiaGxhbWluZXIiKSkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gbWFwKGdlbm90eXBlciwgZnVuY3Rpb24oeCkgc3VwcHJlc3NNZXNzYWdlcyhyZWFkX3RzdigiLi4vLi4vY292aWQvaXNiL3NjSExBY291bnQvQkxfZmFzdHFfZmlsZXMudHh0IiwgY29sX25hbWVzID0gInNhbXBsZSIpKSkpICU+JSAgLS0+CjwhLS0gICB1bm5lc3QoZGF0YSkgJT4lICAtLT4KPCEtLSAgIGZpbHRlcihncmVwbChzYW1wLCBzYW1wbGUpKSAlPiUgIC0tPgo8IS0tICAgIyBJbXBvcnQgZGF0YSBiYXNlZCBvbiBzYW1wbGUgYW5kIGdlbm90eXBlciAtLT4KPCEtLSAgIG11dGF0ZShyZXN1bHRfcGF0aCA9IHNwcmludGYoIiVzL291dHB1dC8lcyIsc2NITEFjb3VudF9kaXIsIGdlbm90eXBlciksIC0tPgo8IS0tICAgICAgICAgIGJhcmNvZGVfcGF0aCA9IHNwcmludGYoIiVzL2JhcmNvZGVzIiwgc2NITEFjb3VudF9kaXIpKSAlPiUgIC0tPgo8IS0tICAgIyBoZWFkKDIpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gcG1hcChsaXN0KHNhbXBsZSwgcmVzdWx0X3BhdGgsIGJhcmNvZGVfcGF0aCksIGZ1bmN0aW9uKHMscixiKXsgLS0+CjwhLS0gICAgIHNjSExBX2RhdGFfcHJvY2Vzc2luZyggLS0+CjwhLS0gICAgICAgc2FtcGxlPXMsIC0tPgo8IS0tICAgICAgIHJlc3VsdF9kaXI9ciwgLS0+CjwhLS0gICAgICAgYmFyY29kZV9kaXI9YiAtLT4KPCEtLSAgICAgKSAtLT4KPCEtLSAgIH0pKSAlPiUgdW5uZXN0KGRhdGEpIC0tPgo8IS0tIHJlc2FtcGxlX2RlcHRoIDwtIDUwMCAtLT4KPCEtLSB5IDwtIHggJT4lICAtLT4KPCEtLSAgIGxlZnRfam9pbihzcnQgJT4lIHNlbGVjdChjZWxsdHlwZSwgY2VsbCksIGJ5ID0gImNlbGwiKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKHNhbXBsZSA9IGdzdWIoIl9bQS1aXVswLTldJCIsIiIsc2FtcGxlKSkgJT4lICAtLT4KPCEtLSAgICMgZmlsdGVyKGdlbmUgPT0gIkEiKSAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKCFpcy5uYShjZWxsdHlwZSkpICU+JSAgLS0+CjwhLS0gICB1bml0ZSgiZ3JvdXAiLCBjZWxsdHlwZSwgZ2VuZSwgc2VwID0gIl8iLCByZW1vdmUgPSBGKSAlPiUgIC0tPgo8IS0tICAgIyBtdXRhdGUoZ3JvdXAgPSBjZWxsdHlwZSkgJT4lICAtLT4KPCEtLSAgIGdyb3VwX2J5KGdyb3VwKSAlPiUgbmVzdCgpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoZGF0YSA9IG1hcChkYXRhLCBmdW5jdGlvbih4KXsgLS0+CjwhLS0gICAgIHggJT4lICAtLT4KPCEtLSAgICAgICBncm91cF9ieShzYW1wbGUsIGdlbm90eXBlcikgJT4lICAtLT4KPCEtLSAgICAgICAjIHNhbXBsZV9uKHJlc2FtcGxlX2RlcHRoLCByZXBsYWNlID0gVCkgJT4lICAtLT4KPCEtLSAgICAgICBtdXRhdGUoY29tcGxlbWVudCA9IGdlbmVfc3VtX3R5cGVkIC0gY291bnQsIGV4cGVjdGVkID0gMC41KmdlbmVfc3VtX3R5cGVkKSAlPiUgIC0tPgo8IS0tICAgICAgIHJvd3dpc2UoKSAlPiUgIC0tPgo8IS0tICAgICAgIG11dGF0ZShvYnNlcnZlZCA9IG1heChhY3Jvc3MoYyhjb3VudCwgY29tcGxlbWVudCkpKSkgJT4lICAtLT4KPCEtLSAgICAgICBncm91cF9ieShzYW1wbGUsIGdlbm90eXBlcikgJT4lICAtLT4KPCEtLSAgICAgICBuZXN0KCkgJT4lICAtLT4KPCEtLSAgICAgICBtdXRhdGUoZGF0YSA9IG1hcChkYXRhLCBzY19tZXRhKSkgJT4lICAtLT4KPCEtLSAgICAgICB1bm5lc3QoZGF0YSkgLS0+CjwhLS0gICB9KSkgJT4lICAtLT4KPCEtLSAgIHVubmVzdChkYXRhKSAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIGBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQgPSA0fSAtLT4KPCEtLSB5IDwtIHkgJT4lICAtLT4KPCEtLSAgIHNlcGFyYXRlKGdyb3VwLCBpbnRvID0gYygiY2VsbHR5cGUiLCAiZ2VuZSIpLCBzZXAgPSAiXyIpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoZ3JvdXAgPSBmYWN0b3IoY2VsbHR5cGUsIGxldmVscyA9IGMoIC0tPgo8IS0tICAgICAiY0RDIiwgIkNEMTQgTW9ub2N5dGUiLCAiQiIsICJwREMiLCAiQ0QxNiBNb25vY3l0ZSIsICJDRDggVCIsICJDRDQgVCIsICJOSyIgLS0+CjwhLS0gICApKSkgLS0+CjwhLS0geSAlPiUgIC0tPgo8IS0tICAgdW5ncm91cCgpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoZ2Vub3R5cGVyID0gcmVmb3JtYXRfaGxhX2dlbm90eXBlcihnZW5vdHlwZXIpKSAlPiUgIC0tPgo8IS0tICAgZ2dwbG90KGFlcyh4ID0gZ2Vub3R5cGVyLCB5ID0gVEUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyLCBmaWxsID0gZ3JvdXApKSsgLS0+CjwhLS0gICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjI1KSsgLS0+CjwhLS0gICBnZW9tX2Vycm9yYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgd2lkdGggPTAuNSkrIC0tPgo8IS0tICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikrIC0tPgo8IS0tICAgdGhlbWVfYncoKSsgLS0+CjwhLS0gICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArIC0tPgo8IS0tICAgbGFicyh5ID0gIk9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCkgKyAtLT4KPCEtLSAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSAtLT4KCjwhLS0geSAlPiUgIC0tPgo8IS0tICAgdW5ncm91cCgpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoZ2Vub3R5cGVyID0gcmVmb3JtYXRfaGxhX2dlbm90eXBlcihnZW5vdHlwZXIpKSAlPiUgIC0tPgo8IS0tICAgZ2dwbG90KGFlcyh4ID0gZ2Vub3R5cGVyLCB5ID0gVEUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyLCBmaWxsID0gZ3JvdXApKSsgLS0+CjwhLS0gICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjI1KSsgLS0+CjwhLS0gICBnZW9tX2Vycm9yYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgd2lkdGggPTAuNSkrIC0tPgo8IS0tICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikrIC0tPgo8IS0tICAgdGhlbWVfYncoKSsgLS0+CjwhLS0gICBmYWNldF93cmFwKH5ncm91cCwgbmNvbCA9IDQpKyAtLT4KPCEtLSAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsgLS0+CjwhLS0gICBsYWJzKHkgPSAiT2RkcyByYXRpbyBvZiBkb21pbmFudCBhbGxlbGUiLCB4PSBOVUxMKSArIC0tPgo8IS0tICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpIC0tPgoKPCEtLSB5ICU+JSAgLS0+CjwhLS0gICB1bmdyb3VwKCkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKHggPSBncm91cCwgeSA9IFRFLCB5bWluID0gbG93ZXIsIHltYXggPSB1cHBlciwgZmlsbCA9IGNlbGx0eXBlKSkrIC0tPgo8IS0tICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yNSkrIC0tPgo8IS0tICAgZ2VvbV9lcnJvcmJhcihwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSksIHdpZHRoID0wLjUpKyAtLT4KPCEtLSAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIpKyAtLT4KPCEtLSAgIHRoZW1lX2J3KCkrIC0tPgo8IS0tICAgZmFjZXRfZ3JpZChnZW5lfmdlbm90eXBlciwgc2NhbGVzID0gImZyZWVfeSIpKyAtLT4KPCEtLSAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsgLS0+CjwhLS0gICBsYWJzKHkgPSAiT2RkcyByYXRpbyBvZiBkb21pbmFudCBhbGxlbGUiLCB4PSBOVUxMKSArIC0tPgo8IS0tICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpIC0tPgoKPCEtLSB5ICU+JSAgLS0+CjwhLS0gICB1bmdyb3VwKCkgJT4lICAtLT4KPCEtLSAgIGZpbHRlcihncm91cCA9PSAicERDIikgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKHggPSBnZW5vdHlwZXIsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIpKSsgLS0+CjwhLS0gICBnZW9tX3BvaW50KCkrIC0tPgo8IS0tICAgZ2VvbV9lcnJvcmJhcigpKyAtLT4KPCEtLSAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIpKyAtLT4KPCEtLSAgIHRoZW1lX2J3KCkrIC0tPgo8IS0tICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyAtLT4KPCEtLSAgIGxhYnMoeSA9ICJPZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwpIC0tPgo8IS0tIGBgYCAtLT4KCgoKCjwhLS0gIyBBc3NlbWJsZSBwbG90IC0tPgo8IS0tIGBgYHtyLCBmaWcud2lkdGggPSAxNCwgZmlnLmhlaWdodCA9IDZ9IC0tPgo8IS0tICMgcGx0X2FsbGVsZV9mcmVxX2xnZCA8LSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9hbGxlbGVfZnJlcSkgLS0+CjwhLS0gIyBwbHRfbWF4X2FsbGVsZV9sZ2QgPC0gY293cGxvdDo6Z2V0X2xlZ2VuZChwbHRfbWF4X2FsbGVsZSkgLS0+CjwhLS0gY29sXzEgPC0gcGxvdF9ncmlkKCAtLT4KPCEtLSAgIHBsdF9hbGxlbGVfZnJlcSwgLS0+CjwhLS0gICBwbHRfbWF4X2FsbGVsZSwgLS0+CjwhLS0gICBuY29sID0gMSwgLS0+CjwhLS0gICByZWxfaGVpZ2h0cyA9IGMoNSwzKSwgLS0+CjwhLS0gICBhbGlnbiA9ICJ2IiwgYXhpcyA9ICJsciIsIC0tPgo8IS0tICAgbGFiZWxzID0gTEVUVEVSU1sxOjJdIC0tPgo8IS0tICkgLS0+Cgo8IS0tIGNvbF8yIDwtIHBsb3RfZ3JpZCggLS0+CjwhLS0gICBwbHRfc3J0LCAtLT4KPCEtLSAgIHBsdF9tZXRhLCAtLT4KPCEtLSAgIG5jb2wgPSAxLCAtLT4KPCEtLSAgIGFsaWduID0gInYiLCBheGlzID0gImxyIiwgLS0+CjwhLS0gICBsYWJlbHMgPSBMRVRURVJTWzM6NF0sIC0tPgo8IS0tICAgaGp1c3QgPSAwLjUgLS0+CjwhLS0gKSAtLT4KPCEtLSBwbG90X2dyaWQoIC0tPgo8IS0tICAgY29sXzEsIC0tPgo8IS0tICAgY29sXzIsICAtLT4KPCEtLSAgIG5yb3cgPSAxLCAtLT4KPCEtLSAgIHJlbF93aWR0aHMgPSBjKDYsMykgLS0+CjwhLS0gKSAtLT4KPCEtLSBgYGAgLS0+CgoKCgoKCgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBnIDwtIGdncGxvdF9idWlsZChwbHRfc3J0KSAtLT4KCjwhLS0gcGx0X2lkcyA8LSBnJGRhdGFbWzFdXSAtLT4KPCEtLSBncm91cF9sZXZlbHMgPC0gbGV2ZWxzKGZhY3RvcihnJHBsb3QkZGF0YVtbZyRwbG90JGxhYmVscyRjb2xvdXJdXSkpIC0tPgoKPCEtLSBwbHRfa2V5IDwtIGckZGF0YVtbMV1dICU+JSAgLS0+CjwhLS0gICBzZWxlY3QoY29sb3VyLCBncm91cCkgJT4lICAtLT4KPCEtLSAgIGRpc3RpbmN0KCkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShsYWJlbCA9IG1hcF9jaHIoZ3JvdXAsIGZ1bmN0aW9uKHgpIGdyb3VwX2xldmVsc1t4XSkpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUobGFiZWwgPSBmYWN0b3IobGFiZWwsIGxldmVsID0gZ3JvdXBfbGV2ZWxzKSkgJT4lIC0tPgo8IS0tICAgbXV0YXRlKGxhYmVsID0gc3ByaW50ZigiJXMpICVzIiwgMTpuKCksIGxhYmVsKSkgJT4lICAtLT4KPCEtLSAgIHNlbGVjdCgtZ3JvdXApIC0tPgoKPCEtLSAgICMgbGV2ZWxzKGZhY3RvcihnJHBsb3QkZGF0YVtbZyRwbG90JGxhYmVscyRjb2xvdXJdXSkpIC0tPgo8IS0tICAgIyBkYXRhLmZyYW1lKGNvbG91cnMgPSB1bmlxdWUoZyRkYXRhW1sxXV1bImNvbG91ciJdKSwgIC0tPgo8IS0tICAgIyAgICAgICAgICAgICAgbGFiZWwgPSBsZXZlbHMoZmFjdG9yKGckcGxvdCRkYXRhW1tnJHBsb3QkbGFiZWxzJGNvbG91cl1dKSkpICU+JSAgLS0+Cgo8IS0tIHBsdF9kZiA8LSBwbHRfaWRzICU+JSAgLS0+CjwhLS0gICBsZWZ0X2pvaW4ocGx0X2tleSwgYnkgPSAiY29sb3VyIikgLS0+Cgo8IS0tIHBsdF9jZW50ZXIgPC0gcGx0X2RmICU+JSAgLS0+CjwhLS0gICBncm91cF9ieShsYWJlbCkgJT4lIHN1bW1hcmlzZSh4ID0gbWVhbih4KSwgeSA9IG1lYW4oeSkpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShsYWJlbCA9IGdzdWIoIikuKiIsIiIsbGFiZWwpKSAtLT4KCjwhLS0gcGx0X3JlcGVsIDwtIHBsdF9kZiAlPiUgIC0tPgo8IS0tICAgZ2dwbG90KGFlcyh4PXgseT15LGNvbG9yPWxhYmVsKSkgKyAtLT4KPCEtLSAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkrIC0tPgo8IS0tICAgIyBnZW9tX3BvaW50KGRhdGEgPSBwbHRfY2VudGVyLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAyKSAtLT4KPCEtLSAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhPXBsdF9jZW50ZXIsYWVzKGxhYmVsPWxhYmVsLCAgYmcuY29sb3I9IndoaXRlIiwgYmcucj0wLjI1LG1pbi5zZWdtZW50Lmxlbmd0aCA9IDApLGNvbG9yID0gImJsYWNrIixmb250ZmFjZSA9ICJib2xkIikgKyAtLT4KPCEtLSAgIHRoZW1lX2J3KCkgKyAtLT4KPCEtLSAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAyKSApICkgKyAtLT4KPCEtLSAgIGxhYnMoeD0iVU1BUCAxIiwgeSA9ICJVTUFQIDIiLCBjb2xvciA9ICJDZWxsIENsdXN0ZXIiKSArIC0tPgo8IS0tICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSsgIC0tPgo8IS0tICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpKSAtLT4KPCEtLSBwbHRfcmVwZWwgLS0+Cgo8IS0tIGBgYCAtLT4KCgoKCgoK